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$ $
31 #include "pim_iface.h"
33 #include "pim_mroute.h"
37 #include "pim_neighbor.h"
38 #include "pim_ifchannel.h"
41 #include "pim_ssmpingd.h"
43 static void pim_if_igmp_join_del_all(struct interface *ifp);
45 static void *if_list_clean(struct pim_interface *pim_ifp)
47 if (pim_ifp->igmp_join_list) {
48 list_delete(pim_ifp->igmp_join_list);
51 if (pim_ifp->igmp_socket_list) {
52 list_delete(pim_ifp->igmp_socket_list);
55 if (pim_ifp->pim_neighbor_list) {
56 list_delete(pim_ifp->pim_neighbor_list);
59 if (pim_ifp->pim_ifchannel_list) {
60 list_delete(pim_ifp->pim_ifchannel_list);
63 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
68 struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
70 struct pim_interface *pim_ifp;
75 pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
77 zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp));
82 pim_ifp->mroute_vif_index = -1;
84 pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
85 pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
86 pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
87 pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
90 RFC 3376: 8.3. Query Response Interval
91 The number of seconds represented by the [Query Response Interval]
92 must be less than the [Query Interval].
94 zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
97 PIM_IF_DO_PIM(pim_ifp->options);
99 PIM_IF_DO_IGMP(pim_ifp->options);
102 /* FIXME: Should join? */
103 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
106 pim_ifp->igmp_join_list = 0;
107 pim_ifp->igmp_socket_list = 0;
108 pim_ifp->pim_neighbor_list = 0;
109 pim_ifp->pim_ifchannel_list = 0;
110 pim_ifp->pim_generation_id = 0;
112 /* list of struct igmp_sock */
113 pim_ifp->igmp_socket_list = list_new();
114 if (!pim_ifp->igmp_socket_list) {
115 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
116 __FILE__, __PRETTY_FUNCTION__);
117 return if_list_clean(pim_ifp);
119 pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free;
121 /* list of struct pim_neighbor */
122 pim_ifp->pim_neighbor_list = list_new();
123 if (!pim_ifp->pim_neighbor_list) {
124 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
125 __FILE__, __PRETTY_FUNCTION__);
126 return if_list_clean(pim_ifp);
128 pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free;
130 /* list of struct pim_ifchannel */
131 pim_ifp->pim_ifchannel_list = list_new();
132 if (!pim_ifp->pim_ifchannel_list) {
133 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
134 __FILE__, __PRETTY_FUNCTION__);
135 return if_list_clean(pim_ifp);
137 pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
143 zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options));
145 if (PIM_MROUTE_IS_ENABLED) {
152 void pim_if_delete(struct interface *ifp)
154 struct pim_interface *pim_ifp;
160 if (pim_ifp->igmp_join_list) {
161 pim_if_igmp_join_del_all(ifp);
163 zassert(!pim_ifp->igmp_join_list);
165 zassert(pim_ifp->igmp_socket_list);
166 zassert(!listcount(pim_ifp->igmp_socket_list));
168 zassert(pim_ifp->pim_neighbor_list);
169 zassert(!listcount(pim_ifp->pim_neighbor_list));
171 zassert(pim_ifp->pim_ifchannel_list);
172 zassert(!listcount(pim_ifp->pim_ifchannel_list));
174 if (PIM_MROUTE_IS_ENABLED) {
178 list_delete(pim_ifp->igmp_socket_list);
179 list_delete(pim_ifp->pim_neighbor_list);
180 list_delete(pim_ifp->pim_ifchannel_list);
182 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
187 void pim_if_update_could_assert(struct interface *ifp)
189 struct pim_interface *pim_ifp;
190 struct listnode *node;
191 struct listnode *next_node;
192 struct pim_ifchannel *ch;
197 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
198 pim_ifchannel_update_could_assert(ch);
202 static void pim_if_update_my_assert_metric(struct interface *ifp)
204 struct pim_interface *pim_ifp;
205 struct listnode *node;
206 struct listnode *next_node;
207 struct pim_ifchannel *ch;
212 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
213 pim_ifchannel_update_my_assert_metric(ch);
217 static void pim_addr_change(struct interface *ifp)
219 struct pim_interface *pim_ifp;
224 pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes -- Done TODO T30 */
225 pim_if_update_join_desired(pim_ifp); /* depends on DR */
226 pim_if_update_could_assert(ifp); /* depends on DR */
227 pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
228 pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */
231 RFC 4601: 4.3.1. Sending Hello Messages
233 1) Before an interface goes down or changes primary IP address, a
234 Hello message with a zero HoldTime should be sent immediately
235 (with the old IP address if the IP address changed).
236 -- FIXME See CAVEAT C13
238 2) After an interface has changed its IP address, it MUST send a
239 Hello message with its new IP address.
242 3) If an interface changes one of its secondary IP addresses, a
243 Hello message with an updated Address_List option and a non-zero
244 HoldTime should be sent immediately.
245 -- FIXME See TODO T31
247 pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */
248 if (pim_ifp->pim_sock_fd < 0)
250 pim_hello_restart_now(ifp); /* send hello and restart timer */
253 static int detect_primary_address_change(struct interface *ifp,
254 int force_prim_as_any,
257 struct pim_interface *pim_ifp;
258 struct in_addr new_prim_addr;
265 if (force_prim_as_any)
266 new_prim_addr = qpim_inaddr_any;
268 new_prim_addr = pim_find_primary_addr(ifp);
270 changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
272 if (PIM_DEBUG_ZEBRA) {
273 char new_prim_str[100];
274 char old_prim_str[100];
275 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
276 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
277 zlog_debug("%s: old=%s new=%s on interface %s: %s",
279 old_prim_str, new_prim_str, ifp->name,
280 changed ? "changed" : "unchanged");
284 pim_ifp->primary_address = new_prim_addr;
286 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
290 pim_addr_change(ifp);
296 static void detect_secondary_address_change(struct interface *ifp,
299 struct pim_interface *pim_ifp;
306 changed = 1; /* true */
308 zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
309 __PRETTY_FUNCTION__, ifp->name);
315 if (!PIM_IF_TEST_PIM(pim_ifp->options)) {
319 pim_addr_change(ifp);
322 static void detect_address_change(struct interface *ifp,
323 int force_prim_as_any,
328 prim_changed = detect_primary_address_change(ifp, force_prim_as_any, caller);
330 /* no need to detect secondary change because
331 the reaction would be the same */
335 detect_secondary_address_change(ifp, caller);
338 void pim_if_addr_add(struct connected *ifc)
340 struct pim_interface *pim_ifp;
341 struct interface *ifp;
342 struct in_addr ifaddr;
352 if (!if_is_operative(ifp))
355 if (PIM_DEBUG_ZEBRA) {
357 prefix2str(ifc->address, buf, BUFSIZ);
358 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
360 ifp->name, ifp->ifindex, buf,
361 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
362 "secondary" : "primary");
365 ifaddr = ifc->address->u.prefix4;
367 detect_address_change(ifp, 0, __PRETTY_FUNCTION__);
369 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
370 struct igmp_sock *igmp;
372 /* lookup IGMP socket */
373 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
376 /* if addr new, add IGMP socket */
377 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
381 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
383 /* Interface has a valid primary address ? */
384 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
386 /* Interface has a valid socket ? */
387 if (pim_ifp->pim_sock_fd < 0) {
388 if (pim_sock_add(ifp)) {
389 zlog_warn("Failure creating PIM socket for interface %s",
397 if (PIM_MROUTE_IS_ENABLED) {
399 PIM or IGMP is enabled on interface, and there is at least one
400 address assigned, then try to create a vif_index.
402 if (pim_ifp->mroute_vif_index < 0) {
408 static void pim_if_addr_del_igmp(struct connected *ifc)
410 struct pim_interface *pim_ifp = ifc->ifp->info;
411 struct igmp_sock *igmp;
412 struct in_addr ifaddr;
414 if (ifc->address->family != AF_INET) {
415 /* non-IPv4 address */
420 /* IGMP not enabled on interface */
424 ifaddr = ifc->address->u.prefix4;
426 /* lookup IGMP socket */
427 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
430 /* if addr found, del IGMP socket */
431 igmp_sock_delete(igmp);
435 static void pim_if_addr_del_pim(struct connected *ifc)
437 struct pim_interface *pim_ifp = ifc->ifp->info;
439 if (ifc->address->family != AF_INET) {
440 /* non-IPv4 address */
445 /* PIM not enabled on interface */
449 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
450 /* Interface keeps a valid primary address */
454 if (pim_ifp->pim_sock_fd < 0) {
455 /* Interface does not hold a valid socket any longer */
460 pim_sock_delete() closes the socket, stops read and timer threads,
461 and kills all neighbors.
463 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
466 void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
468 struct interface *ifp;
474 if (PIM_DEBUG_ZEBRA) {
476 prefix2str(ifc->address, buf, BUFSIZ);
477 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
479 ifp->name, ifp->ifindex, buf,
480 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
481 "secondary" : "primary");
484 detect_address_change(ifp, force_prim_as_any, __PRETTY_FUNCTION__);
486 pim_if_addr_del_igmp(ifc);
487 pim_if_addr_del_pim(ifc);
490 void pim_if_addr_add_all(struct interface *ifp)
492 struct connected *ifc;
493 struct listnode *node;
494 struct listnode *nextnode;
496 /* PIM/IGMP enabled ? */
500 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
501 struct prefix *p = ifc->address;
503 if (p->family != AF_INET)
506 pim_if_addr_add(ifc);
510 void pim_if_addr_del_all(struct interface *ifp)
512 struct connected *ifc;
513 struct listnode *node;
514 struct listnode *nextnode;
516 /* PIM/IGMP enabled ? */
520 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
521 struct prefix *p = ifc->address;
523 if (p->family != AF_INET)
526 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
530 void pim_if_addr_del_all_igmp(struct interface *ifp)
532 struct connected *ifc;
533 struct listnode *node;
534 struct listnode *nextnode;
536 /* PIM/IGMP enabled ? */
540 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
541 struct prefix *p = ifc->address;
543 if (p->family != AF_INET)
546 pim_if_addr_del_igmp(ifc);
550 void pim_if_addr_del_all_pim(struct interface *ifp)
552 struct connected *ifc;
553 struct listnode *node;
554 struct listnode *nextnode;
556 /* PIM/IGMP enabled ? */
560 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
561 struct prefix *p = ifc->address;
563 if (p->family != AF_INET)
566 pim_if_addr_del_pim(ifc);
570 static struct in_addr find_first_nonsec_addr(struct interface *ifp)
572 struct connected *ifc;
573 struct listnode *node;
576 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
577 struct prefix *p = ifc->address;
579 if (p->family != AF_INET)
582 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
583 zlog_warn("%s: null IPv4 address connected to interface %s",
584 __PRETTY_FUNCTION__, ifp->name);
588 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
594 addr.s_addr = PIM_NET_INADDR_ANY;
599 struct in_addr pim_find_primary_addr(struct interface *ifp)
601 return find_first_nonsec_addr(ifp);
605 pim_if_add_vif() uses ifindex as vif_index
607 see also pim_if_find_vifindex_by_ifindex()
609 int pim_if_add_vif(struct interface *ifp)
611 struct pim_interface *pim_ifp = ifp->info;
612 struct in_addr ifaddr;
616 if (pim_ifp->mroute_vif_index > 0) {
617 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
619 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
623 if (ifp->ifindex < 1) {
624 zlog_warn("%s: ifindex=%d < 1 on interface %s",
626 ifp->ifindex, ifp->name);
630 if (ifp->ifindex >= MAXVIFS) {
631 zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
633 ifp->ifindex, MAXVIFS, ifp->name);
637 ifaddr = pim_ifp->primary_address;
638 if (PIM_INADDR_IS_ANY(ifaddr)) {
639 zlog_warn("%s: could not get address for interface %s ifindex=%d",
641 ifp->name, ifp->ifindex);
645 if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) {
646 /* pim_mroute_add_vif reported error */
650 pim_ifp->mroute_vif_index = ifp->ifindex;
653 Update highest vif_index
655 if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) {
656 qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index;
662 static int iflist_find_highest_vif_index()
664 struct listnode *ifnode;
665 struct interface *ifp;
666 struct pim_interface *pim_ifp;
667 int highest_vif_index = -1;
669 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
674 if (pim_ifp->mroute_vif_index > highest_vif_index) {
675 highest_vif_index = pim_ifp->mroute_vif_index;
679 return highest_vif_index;
682 int pim_if_del_vif(struct interface *ifp)
684 struct pim_interface *pim_ifp = ifp->info;
687 if (pim_ifp->mroute_vif_index < 1) {
688 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
690 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
694 if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
695 /* pim_mroute_del_vif reported error */
700 Update highest vif_index
703 /* save old vif_index in order to compare with highest below */
704 old_vif_index = pim_ifp->mroute_vif_index;
706 pim_ifp->mroute_vif_index = -1;
708 if (old_vif_index == qpim_mroute_oif_highest_vif_index) {
709 qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index();
715 void pim_if_add_vif_all()
717 struct listnode *ifnode;
718 struct listnode *ifnextnode;
719 struct interface *ifp;
721 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
729 void pim_if_del_vif_all()
731 struct listnode *ifnode;
732 struct listnode *ifnextnode;
733 struct interface *ifp;
735 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
743 struct interface *pim_if_find_by_vif_index(int vif_index)
745 struct listnode *ifnode;
746 struct interface *ifp;
748 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
750 struct pim_interface *pim_ifp;
752 if (vif_index == pim_ifp->mroute_vif_index)
761 pim_if_add_vif() uses ifindex as vif_index
763 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex)
768 int pim_if_lan_delay_enabled(struct interface *ifp)
770 struct pim_interface *pim_ifp;
774 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
776 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
779 uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
781 if (pim_if_lan_delay_enabled(ifp)) {
782 struct pim_interface *pim_ifp;
784 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
787 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
791 uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
793 if (pim_if_lan_delay_enabled(ifp)) {
794 struct pim_interface *pim_ifp;
796 return pim_ifp->pim_neighbors_highest_override_interval_msec;
799 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
803 int pim_if_t_override_msec(struct interface *ifp)
805 int effective_override_interval_msec;
808 effective_override_interval_msec =
809 pim_if_effective_override_interval_msec(ifp);
811 t_override_msec = random() % (effective_override_interval_msec + 1);
813 return t_override_msec;
816 uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
818 return pim_if_effective_propagation_delay_msec(ifp) +
819 pim_if_effective_override_interval_msec(ifp);
823 RFC 4601: 4.1.6. State Summarization Macros
825 The function NBR( I, A ) uses information gathered through PIM Hello
826 messages to map the IP address A of a directly connected PIM
827 neighbor router on interface I to the primary IP address of the same
828 router (Section 4.3.4). The primary IP address of a neighbor is the
829 address that it uses as the source of its PIM Hello messages.
831 struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
834 struct listnode *neighnode;
835 struct pim_neighbor *neigh;
836 struct pim_interface *pim_ifp;
842 zlog_warn("%s: multicast not enabled on interface %s",
848 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
850 /* primary address ? */
851 if (neigh->source_addr.s_addr == addr.s_addr)
854 /* secondary address ? */
855 if (pim_neighbor_find_secondary(neigh, addr))
859 if (PIM_DEBUG_PIM_TRACE) {
861 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
862 zlog_debug("%s: neighbor not found for address %s on interface %s",
864 addr_str, ifp->name);
870 long pim_if_t_suppressed_msec(struct interface *ifp)
872 struct pim_interface *pim_ifp;
873 long t_suppressed_msec;
874 uint32_t ramount = 0;
879 /* join suppression disabled ? */
880 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
883 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
884 ramount = 1100 + (random() % (1400 - 1100 + 1));
885 t_suppressed_msec = qpim_t_periodic * ramount;
887 return t_suppressed_msec;
890 static void igmp_join_free(struct igmp_join *ij)
892 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
895 static struct igmp_join *igmp_join_find(struct list *join_list,
896 struct in_addr group_addr,
897 struct in_addr source_addr)
899 struct listnode *node;
900 struct igmp_join *ij;
904 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
905 if ((group_addr.s_addr == ij->group_addr.s_addr) &&
906 (source_addr.s_addr == ij->source_addr.s_addr))
913 static int igmp_join_sock(const char *ifname,
915 struct in_addr group_addr,
916 struct in_addr source_addr)
920 join_fd = pim_socket_raw(IPPROTO_IGMP);
925 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
933 static struct igmp_join *igmp_join_new(struct interface *ifp,
934 struct in_addr group_addr,
935 struct in_addr source_addr)
937 struct pim_interface *pim_ifp;
938 struct igmp_join *ij;
944 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
947 char source_str[100];
948 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
949 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
950 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
952 group_str, source_str, ifp->name);
956 ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
959 char source_str[100];
960 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
961 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
962 zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
964 sizeof(*ij), group_str, source_str, ifp->name);
969 ij->sock_fd = join_fd;
970 ij->group_addr = group_addr;
971 ij->source_addr = source_addr;
972 ij->sock_creation = pim_time_monotonic_sec();
974 listnode_add(pim_ifp->igmp_join_list, ij);
979 int pim_if_igmp_join_add(struct interface *ifp,
980 struct in_addr group_addr,
981 struct in_addr source_addr)
983 struct pim_interface *pim_ifp;
984 struct igmp_join *ij;
988 zlog_warn("%s: multicast not enabled on interface %s",
994 if (!pim_ifp->igmp_join_list) {
995 pim_ifp->igmp_join_list = list_new();
996 if (!pim_ifp->igmp_join_list) {
997 zlog_err("%s %s: failure: igmp_join_list=list_new()",
998 __FILE__, __PRETTY_FUNCTION__);
1001 pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
1004 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1006 char group_str[100];
1007 char source_str[100];
1008 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1009 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1010 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1011 __PRETTY_FUNCTION__,
1012 group_str, source_str, ifp->name);
1016 ij = igmp_join_new(ifp, group_addr, source_addr);
1018 char group_str[100];
1019 char source_str[100];
1020 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1021 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1022 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1023 __PRETTY_FUNCTION__,
1024 group_str, source_str, ifp->name);
1028 if (PIM_DEBUG_IGMP_EVENTS) {
1029 char group_str[100];
1030 char source_str[100];
1031 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1032 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1033 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1034 __PRETTY_FUNCTION__,
1035 source_str, group_str, ifp->name);
1043 int pim_if_igmp_join_del(struct interface *ifp,
1044 struct in_addr group_addr,
1045 struct in_addr source_addr)
1047 struct pim_interface *pim_ifp;
1048 struct igmp_join *ij;
1050 pim_ifp = ifp->info;
1052 zlog_warn("%s: multicast not enabled on interface %s",
1053 __PRETTY_FUNCTION__,
1058 if (!pim_ifp->igmp_join_list) {
1059 zlog_warn("%s: no IGMP join on interface %s",
1060 __PRETTY_FUNCTION__,
1065 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1067 char group_str[100];
1068 char source_str[100];
1069 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1070 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1071 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1072 __PRETTY_FUNCTION__,
1073 group_str, source_str, ifp->name);
1077 if (close(ij->sock_fd)) {
1079 char group_str[100];
1080 char source_str[100];
1081 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1082 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1083 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1084 __PRETTY_FUNCTION__,
1085 ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
1088 listnode_delete(pim_ifp->igmp_join_list, ij);
1090 if (listcount(pim_ifp->igmp_join_list) < 1) {
1091 list_delete(pim_ifp->igmp_join_list);
1092 pim_ifp->igmp_join_list = 0;
1098 static void pim_if_igmp_join_del_all(struct interface *ifp)
1100 struct pim_interface *pim_ifp;
1101 struct listnode *node;
1102 struct listnode *nextnode;
1103 struct igmp_join *ij;
1105 pim_ifp = ifp->info;
1107 zlog_warn("%s: multicast not enabled on interface %s",
1108 __PRETTY_FUNCTION__,
1113 if (!pim_ifp->igmp_join_list)
1116 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1117 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1123 Transitions from "I am Assert Loser" State
1125 Current Winner's GenID Changes or NLT Expires
1127 The Neighbor Liveness Timer associated with the current winner
1128 expires or we receive a Hello message from the current winner
1129 reporting a different GenID from the one it previously reported.
1130 This indicates that the current winner's interface or router has
1131 gone down (and may have come back up), and so we must assume it no
1132 longer knows it was the winner.
1134 void pim_if_assert_on_neighbor_down(struct interface *ifp,
1135 struct in_addr neigh_addr)
1137 struct pim_interface *pim_ifp;
1138 struct listnode *node;
1139 struct listnode *next_node;
1140 struct pim_ifchannel *ch;
1142 pim_ifp = ifp->info;
1145 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1146 /* Is (S,G,I) assert loser ? */
1147 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1149 /* Dead neighbor was winner ? */
1150 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1153 assert_action_a5(ch);
1157 void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1159 struct listnode *ch_node;
1160 struct pim_ifchannel *ch;
1162 /* clear off flag from interface's upstreams */
1163 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1164 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1167 /* scan per-interface (S,G,I) state on this I interface */
1168 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1169 struct pim_upstream *up = ch->upstream;
1171 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1174 /* update join_desired for the global (S,G) state */
1175 pim_upstream_update_join_desired(up);
1176 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1180 void pim_if_update_assert_tracking_desired(struct interface *ifp)
1182 struct pim_interface *pim_ifp;
1183 struct listnode *node;
1184 struct listnode *next_node;
1185 struct pim_ifchannel *ch;
1187 pim_ifp = ifp->info;
1191 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1192 pim_ifchannel_update_assert_tracking_desired(ch);