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"
43 #include "pim_ssmpingd.h"
45 static void pim_if_igmp_join_del_all(struct interface
*ifp
);
49 vrf_iflist_create(VRF_DEFAULT
);
52 static void *if_list_clean(struct pim_interface
*pim_ifp
)
54 if (pim_ifp
->igmp_join_list
) {
55 list_delete(pim_ifp
->igmp_join_list
);
58 if (pim_ifp
->igmp_socket_list
) {
59 list_delete(pim_ifp
->igmp_socket_list
);
62 if (pim_ifp
->pim_neighbor_list
) {
63 list_delete(pim_ifp
->pim_neighbor_list
);
66 if (pim_ifp
->pim_ifchannel_list
) {
67 list_delete(pim_ifp
->pim_ifchannel_list
);
70 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
75 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
77 struct pim_interface
*pim_ifp
;
82 pim_ifp
= XMALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
84 zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp
));
89 pim_ifp
->mroute_vif_index
= -1;
91 pim_ifp
->igmp_default_robustness_variable
= IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
92 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
93 pim_ifp
->igmp_query_max_response_time_dsec
= IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
94 pim_ifp
->igmp_specific_query_max_response_time_dsec
= IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
97 RFC 3376: 8.3. Query Response Interval
98 The number of seconds represented by the [Query Response Interval]
99 must be less than the [Query Interval].
101 zassert(pim_ifp
->igmp_query_max_response_time_dsec
< pim_ifp
->igmp_default_query_interval
);
104 PIM_IF_DO_PIM(pim_ifp
->options
);
106 PIM_IF_DO_IGMP(pim_ifp
->options
);
109 /* FIXME: Should join? */
110 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
113 pim_ifp
->igmp_join_list
= 0;
114 pim_ifp
->igmp_socket_list
= 0;
115 pim_ifp
->pim_neighbor_list
= 0;
116 pim_ifp
->pim_ifchannel_list
= 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 zassert(PIM_IF_TEST_PIM(pim_ifp
->options
) || PIM_IF_TEST_IGMP(pim_ifp
->options
));
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 void on_primary_address_change(struct interface
*ifp
,
261 struct in_addr old_addr
,
262 struct in_addr new_addr
)
264 struct pim_interface
*pim_ifp
;
269 pim_inet4_dump("<old?>", old_addr
, old_str
, sizeof(old_str
));
270 pim_inet4_dump("<new?>", new_addr
, new_str
, sizeof(new_str
));
271 zlog_info("%s: %s: primary address changed from %s to %s on interface %s",
272 __PRETTY_FUNCTION__
, caller
,
273 old_str
, new_str
, ifp
->name
);
281 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
285 pim_addr_change(ifp
);
288 static int detect_primary_address_change(struct interface
*ifp
,
289 int force_prim_as_any
,
292 struct pim_interface
*pim_ifp
;
293 struct in_addr new_prim_addr
;
300 if (force_prim_as_any
)
301 new_prim_addr
= qpim_inaddr_any
;
303 new_prim_addr
= pim_find_primary_addr(ifp
);
305 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
307 if (PIM_DEBUG_ZEBRA
) {
308 char new_prim_str
[100];
309 char old_prim_str
[100];
310 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
, sizeof(new_prim_str
));
311 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
, sizeof(old_prim_str
));
312 zlog_debug("%s: old=%s new=%s on interface %s: %s",
314 old_prim_str
, new_prim_str
, ifp
->name
,
315 changed
? "changed" : "unchanged");
319 struct in_addr old_addr
= pim_ifp
->primary_address
;
320 pim_ifp
->primary_address
= new_prim_addr
;
322 on_primary_address_change(ifp
, caller
, old_addr
, new_prim_addr
);
328 static void detect_secondary_address_change(struct interface
*ifp
,
331 struct pim_interface
*pim_ifp
;
338 changed
= 1; /* true */
339 zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
340 __PRETTY_FUNCTION__
, ifp
->name
);
342 if (PIM_DEBUG_ZEBRA
) {
343 zlog_debug("%s: on interface %s: %s",
345 ifp
->name
, changed
? "changed" : "unchanged");
352 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
356 pim_addr_change(ifp
);
359 static void detect_address_change(struct interface
*ifp
,
360 int force_prim_as_any
,
365 prim_changed
= detect_primary_address_change(ifp
, force_prim_as_any
, caller
);
367 /* no need to detect secondary change because
368 the reaction would be the same */
372 detect_secondary_address_change(ifp
, caller
);
375 void pim_if_addr_add(struct connected
*ifc
)
377 struct pim_interface
*pim_ifp
;
378 struct interface
*ifp
;
379 struct in_addr ifaddr
;
389 if (!if_is_operative(ifp
))
392 /* if (PIM_DEBUG_ZEBRA) */ {
394 prefix2str(ifc
->address
, buf
, BUFSIZ
);
395 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
397 ifp
->name
, ifp
->ifindex
, buf
,
398 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
399 "secondary" : "primary");
402 ifaddr
= ifc
->address
->u
.prefix4
;
404 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
406 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
407 struct igmp_sock
*igmp
;
409 /* lookup IGMP socket */
410 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
413 /* if addr new, add IGMP socket */
414 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
, ifp
);
418 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
420 /* Interface has a valid primary address ? */
421 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
423 /* Interface has a valid socket ? */
424 if (pim_ifp
->pim_sock_fd
< 0) {
425 if (pim_sock_add(ifp
)) {
426 zlog_warn("Failure creating PIM socket for interface %s",
434 if (PIM_MROUTE_IS_ENABLED
) {
436 PIM or IGMP is enabled on interface, and there is at least one
437 address assigned, then try to create a vif_index.
439 if (pim_ifp
->mroute_vif_index
< 0) {
445 static void pim_if_addr_del_igmp(struct connected
*ifc
)
447 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
448 struct igmp_sock
*igmp
;
449 struct in_addr ifaddr
;
451 if (ifc
->address
->family
!= AF_INET
) {
452 /* non-IPv4 address */
457 /* IGMP not enabled on interface */
461 ifaddr
= ifc
->address
->u
.prefix4
;
463 /* lookup IGMP socket */
464 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
467 /* if addr found, del IGMP socket */
468 igmp_sock_delete(igmp
);
472 static void pim_if_addr_del_pim(struct connected
*ifc
)
474 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
476 if (ifc
->address
->family
!= AF_INET
) {
477 /* non-IPv4 address */
482 /* PIM not enabled on interface */
486 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
487 /* Interface keeps a valid primary address */
491 if (pim_ifp
->pim_sock_fd
< 0) {
492 /* Interface does not hold a valid socket any longer */
497 pim_sock_delete() closes the socket, stops read and timer threads,
498 and kills all neighbors.
500 pim_sock_delete(ifc
->ifp
, "last address has been removed from interface");
503 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
505 struct interface
*ifp
;
511 /* if (PIM_DEBUG_ZEBRA) */ {
513 prefix2str(ifc
->address
, buf
, BUFSIZ
);
514 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
516 ifp
->name
, ifp
->ifindex
, buf
,
517 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
518 "secondary" : "primary");
521 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
523 pim_if_addr_del_igmp(ifc
);
524 pim_if_addr_del_pim(ifc
);
527 void pim_if_addr_add_all(struct interface
*ifp
)
529 struct connected
*ifc
;
530 struct listnode
*node
;
531 struct listnode
*nextnode
;
533 /* PIM/IGMP enabled ? */
537 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
538 struct prefix
*p
= ifc
->address
;
540 if (p
->family
!= AF_INET
)
543 pim_if_addr_add(ifc
);
547 void pim_if_addr_del_all(struct interface
*ifp
)
549 struct connected
*ifc
;
550 struct listnode
*node
;
551 struct listnode
*nextnode
;
553 /* PIM/IGMP enabled ? */
557 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
558 struct prefix
*p
= ifc
->address
;
560 if (p
->family
!= AF_INET
)
563 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
567 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
569 struct connected
*ifc
;
570 struct listnode
*node
;
571 struct listnode
*nextnode
;
573 /* PIM/IGMP enabled ? */
577 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
578 struct prefix
*p
= ifc
->address
;
580 if (p
->family
!= AF_INET
)
583 pim_if_addr_del_igmp(ifc
);
587 void pim_if_addr_del_all_pim(struct interface
*ifp
)
589 struct connected
*ifc
;
590 struct listnode
*node
;
591 struct listnode
*nextnode
;
593 /* PIM/IGMP enabled ? */
597 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
598 struct prefix
*p
= ifc
->address
;
600 if (p
->family
!= AF_INET
)
603 pim_if_addr_del_pim(ifc
);
607 static struct in_addr
find_first_nonsec_addr(struct interface
*ifp
)
609 struct connected
*ifc
;
610 struct listnode
*node
;
613 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
614 struct prefix
*p
= ifc
->address
;
616 if (p
->family
!= AF_INET
)
619 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
620 zlog_warn("%s: null IPv4 address connected to interface %s",
621 __PRETTY_FUNCTION__
, ifp
->name
);
625 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
631 addr
.s_addr
= PIM_NET_INADDR_ANY
;
636 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
638 return find_first_nonsec_addr(ifp
);
642 pim_if_add_vif() uses ifindex as vif_index
644 see also pim_if_find_vifindex_by_ifindex()
646 int pim_if_add_vif(struct interface
*ifp
)
648 struct pim_interface
*pim_ifp
= ifp
->info
;
649 struct in_addr ifaddr
;
653 if (pim_ifp
->mroute_vif_index
> 0) {
654 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
656 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
660 if (ifp
->ifindex
< 1) {
661 zlog_warn("%s: ifindex=%d < 1 on interface %s",
663 ifp
->ifindex
, ifp
->name
);
667 if (ifp
->ifindex
>= MAXVIFS
) {
668 zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
670 ifp
->ifindex
, MAXVIFS
, ifp
->name
);
674 ifaddr
= pim_ifp
->primary_address
;
675 if (PIM_INADDR_IS_ANY(ifaddr
)) {
676 zlog_warn("%s: could not get address for interface %s ifindex=%d",
678 ifp
->name
, ifp
->ifindex
);
682 if (pim_mroute_add_vif(ifp
->ifindex
, ifaddr
)) {
683 /* pim_mroute_add_vif reported error */
687 pim_ifp
->mroute_vif_index
= ifp
->ifindex
;
690 Update highest vif_index
692 if (pim_ifp
->mroute_vif_index
> qpim_mroute_oif_highest_vif_index
) {
693 qpim_mroute_oif_highest_vif_index
= pim_ifp
->mroute_vif_index
;
699 static int iflist_find_highest_vif_index()
701 struct listnode
*ifnode
;
702 struct interface
*ifp
;
703 struct pim_interface
*pim_ifp
;
704 int highest_vif_index
= -1;
706 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
711 if (pim_ifp
->mroute_vif_index
> highest_vif_index
) {
712 highest_vif_index
= pim_ifp
->mroute_vif_index
;
716 return highest_vif_index
;
719 int pim_if_del_vif(struct interface
*ifp
)
721 struct pim_interface
*pim_ifp
= ifp
->info
;
724 if (pim_ifp
->mroute_vif_index
< 1) {
725 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
727 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
731 if (pim_mroute_del_vif(pim_ifp
->mroute_vif_index
)) {
732 /* pim_mroute_del_vif reported error */
737 Update highest vif_index
740 /* save old vif_index in order to compare with highest below */
741 old_vif_index
= pim_ifp
->mroute_vif_index
;
743 pim_ifp
->mroute_vif_index
= -1;
745 if (old_vif_index
== qpim_mroute_oif_highest_vif_index
) {
746 qpim_mroute_oif_highest_vif_index
= iflist_find_highest_vif_index();
752 void pim_if_add_vif_all()
754 struct listnode
*ifnode
;
755 struct listnode
*ifnextnode
;
756 struct interface
*ifp
;
758 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
766 void pim_if_del_vif_all()
768 struct listnode
*ifnode
;
769 struct listnode
*ifnextnode
;
770 struct interface
*ifp
;
772 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
780 struct interface
*pim_if_find_by_vif_index(int vif_index
)
782 struct listnode
*ifnode
;
783 struct interface
*ifp
;
785 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
787 struct pim_interface
*pim_ifp
;
789 if (vif_index
== pim_ifp
->mroute_vif_index
)
798 pim_if_add_vif() uses ifindex as vif_index
800 int pim_if_find_vifindex_by_ifindex(int ifindex
)
805 int pim_if_lan_delay_enabled(struct interface
*ifp
)
807 struct pim_interface
*pim_ifp
;
811 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
813 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
816 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
818 if (pim_if_lan_delay_enabled(ifp
)) {
819 struct pim_interface
*pim_ifp
;
821 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
824 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
828 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
830 if (pim_if_lan_delay_enabled(ifp
)) {
831 struct pim_interface
*pim_ifp
;
833 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
836 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
840 int pim_if_t_override_msec(struct interface
*ifp
)
842 int effective_override_interval_msec
;
845 effective_override_interval_msec
=
846 pim_if_effective_override_interval_msec(ifp
);
848 t_override_msec
= pim_rand_next(0, effective_override_interval_msec
);
850 return t_override_msec
;
853 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
855 return pim_if_effective_propagation_delay_msec(ifp
) +
856 pim_if_effective_override_interval_msec(ifp
);
860 RFC 4601: 4.1.6. State Summarization Macros
862 The function NBR( I, A ) uses information gathered through PIM Hello
863 messages to map the IP address A of a directly connected PIM
864 neighbor router on interface I to the primary IP address of the same
865 router (Section 4.3.4). The primary IP address of a neighbor is the
866 address that it uses as the source of its PIM Hello messages.
868 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
871 struct listnode
*neighnode
;
872 struct pim_neighbor
*neigh
;
873 struct pim_interface
*pim_ifp
;
879 zlog_warn("%s: multicast not enabled on interface %s",
885 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
, neigh
)) {
887 /* primary address ? */
888 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
891 /* secondary address ? */
892 if (pim_neighbor_find_secondary(neigh
, addr
))
896 if (PIM_DEBUG_PIM_TRACE
) {
898 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
899 zlog_debug("%s: neighbor not found for address %s on interface %s",
901 addr_str
, ifp
->name
);
907 long pim_if_t_suppressed_msec(struct interface
*ifp
)
909 struct pim_interface
*pim_ifp
;
910 long t_suppressed_msec
;
915 /* join suppression disabled ? */
916 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
919 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
921 t_suppressed_msec
= qpim_t_periodic
* pim_rand_next(1100, 1400);
923 return t_suppressed_msec
;
926 static void igmp_join_free(struct igmp_join
*ij
)
928 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
931 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
932 struct in_addr group_addr
,
933 struct in_addr source_addr
)
935 struct listnode
*node
;
936 struct igmp_join
*ij
;
940 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
941 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
) &&
942 (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
949 static int igmp_join_sock(const char *ifname
,
951 struct in_addr group_addr
,
952 struct in_addr source_addr
)
956 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
961 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
, ifname
)) {
969 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
970 struct in_addr group_addr
,
971 struct in_addr source_addr
)
973 struct pim_interface
*pim_ifp
;
974 struct igmp_join
*ij
;
980 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
, source_addr
);
983 char source_str
[100];
984 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
985 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
986 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
988 group_str
, source_str
, ifp
->name
);
992 ij
= XMALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
995 char source_str
[100];
996 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
997 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
998 zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1000 sizeof(*ij
), group_str
, source_str
, ifp
->name
);
1005 ij
->sock_fd
= join_fd
;
1006 ij
->group_addr
= group_addr
;
1007 ij
->source_addr
= source_addr
;
1008 ij
->sock_creation
= pim_time_monotonic_sec();
1010 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1015 int pim_if_igmp_join_add(struct interface
*ifp
,
1016 struct in_addr group_addr
,
1017 struct in_addr source_addr
)
1019 struct pim_interface
*pim_ifp
;
1020 struct igmp_join
*ij
;
1022 pim_ifp
= ifp
->info
;
1024 zlog_warn("%s: multicast not enabled on interface %s",
1025 __PRETTY_FUNCTION__
,
1030 if (!pim_ifp
->igmp_join_list
) {
1031 pim_ifp
->igmp_join_list
= list_new();
1032 if (!pim_ifp
->igmp_join_list
) {
1033 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1034 __FILE__
, __PRETTY_FUNCTION__
);
1037 pim_ifp
->igmp_join_list
->del
= (void (*)(void *)) igmp_join_free
;
1040 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1042 char group_str
[100];
1043 char source_str
[100];
1044 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1045 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1046 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1047 __PRETTY_FUNCTION__
,
1048 group_str
, source_str
, ifp
->name
);
1052 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1054 char group_str
[100];
1055 char source_str
[100];
1056 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1057 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1058 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1059 __PRETTY_FUNCTION__
,
1060 group_str
, source_str
, ifp
->name
);
1065 char group_str
[100];
1066 char source_str
[100];
1067 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1068 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1069 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1070 __PRETTY_FUNCTION__
,
1071 source_str
, group_str
, ifp
->name
);
1079 int pim_if_igmp_join_del(struct interface
*ifp
,
1080 struct in_addr group_addr
,
1081 struct in_addr source_addr
)
1083 struct pim_interface
*pim_ifp
;
1084 struct igmp_join
*ij
;
1086 pim_ifp
= ifp
->info
;
1088 zlog_warn("%s: multicast not enabled on interface %s",
1089 __PRETTY_FUNCTION__
,
1094 if (!pim_ifp
->igmp_join_list
) {
1095 zlog_warn("%s: no IGMP join on interface %s",
1096 __PRETTY_FUNCTION__
,
1101 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1103 char group_str
[100];
1104 char source_str
[100];
1105 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1106 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1107 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1108 __PRETTY_FUNCTION__
,
1109 group_str
, source_str
, ifp
->name
);
1113 if (close(ij
->sock_fd
)) {
1115 char group_str
[100];
1116 char source_str
[100];
1117 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1118 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1119 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1120 __PRETTY_FUNCTION__
,
1121 ij
->sock_fd
, group_str
, source_str
, ifp
->name
, e
, safe_strerror(e
));
1124 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1126 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1127 list_delete(pim_ifp
->igmp_join_list
);
1128 pim_ifp
->igmp_join_list
= 0;
1134 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1136 struct pim_interface
*pim_ifp
;
1137 struct listnode
*node
;
1138 struct listnode
*nextnode
;
1139 struct igmp_join
*ij
;
1141 pim_ifp
= ifp
->info
;
1143 zlog_warn("%s: multicast not enabled on interface %s",
1144 __PRETTY_FUNCTION__
,
1149 if (!pim_ifp
->igmp_join_list
)
1152 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1153 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1159 Transitions from "I am Assert Loser" State
1161 Current Winner's GenID Changes or NLT Expires
1163 The Neighbor Liveness Timer associated with the current winner
1164 expires or we receive a Hello message from the current winner
1165 reporting a different GenID from the one it previously reported.
1166 This indicates that the current winner's interface or router has
1167 gone down (and may have come back up), and so we must assume it no
1168 longer knows it was the winner.
1170 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1171 struct in_addr neigh_addr
)
1173 struct pim_interface
*pim_ifp
;
1174 struct listnode
*node
;
1175 struct listnode
*next_node
;
1176 struct pim_ifchannel
*ch
;
1178 pim_ifp
= ifp
->info
;
1181 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1182 /* Is (S,G,I) assert loser ? */
1183 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1185 /* Dead neighbor was winner ? */
1186 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1189 assert_action_a5(ch
);
1193 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1195 struct listnode
*ch_node
;
1196 struct pim_ifchannel
*ch
;
1198 /* clear off flag from interface's upstreams */
1199 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1200 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch
->upstream
->flags
);
1203 /* scan per-interface (S,G,I) state on this I interface */
1204 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1205 struct pim_upstream
*up
= ch
->upstream
;
1207 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1210 /* update join_desired for the global (S,G) state */
1211 pim_upstream_update_join_desired(up
);
1212 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1216 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1218 struct pim_interface
*pim_ifp
;
1219 struct listnode
*node
;
1220 struct listnode
*next_node
;
1221 struct pim_ifchannel
*ch
;
1223 pim_ifp
= ifp
->info
;
1227 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1228 pim_ifchannel_update_assert_tracking_desired(ch
);