3 * Copyright (C) 2008 Everton da Silva Marques
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "pim_zebra.h"
35 #include "pim_iface.h"
41 #include "pim_zlookup.h"
42 #include "pim_ifchannel.h"
44 #include "pim_igmpv3.h"
45 #include "pim_jp_agg.h"
48 #include "pim_vxlan.h"
51 #undef PIM_DEBUG_IFADDR_DUMP
52 #define PIM_DEBUG_IFADDR_DUMP
54 struct zclient
*zclient
;
57 /* Router-id update message from zebra. */
58 static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS
)
60 struct prefix router_id
;
62 zebra_router_id_update_read(zclient
->ibuf
, &router_id
);
67 static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS
)
69 struct interface
*ifp
;
72 ifp
= zebra_interface_vrf_update_read(zclient
->ibuf
, vrf_id
,
78 zlog_debug("%s: %s updating from %u to %u",
80 ifp
->name
, vrf_id
, new_vrf_id
);
82 if_update_to_new_vrf(ifp
, new_vrf_id
);
87 #ifdef PIM_DEBUG_IFADDR_DUMP
88 static void dump_if_address(struct interface
*ifp
)
90 struct connected
*ifc
;
91 struct listnode
*node
;
93 zlog_debug("%s %s: interface %s addresses:", __FILE__
,
94 __PRETTY_FUNCTION__
, ifp
->name
);
96 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
97 struct prefix
*p
= ifc
->address
;
99 if (p
->family
!= AF_INET
)
102 zlog_debug("%s %s: interface %s address %s %s", __FILE__
,
103 __PRETTY_FUNCTION__
, ifp
->name
,
104 inet_ntoa(p
->u
.prefix4
),
105 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
112 static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS
)
116 struct pim_interface
*pim_ifp
;
117 struct pim_instance
*pim
;
120 zebra api notifies address adds/dels events by using the same call
121 interface_add_read below, see comments in lib/zclient.c
123 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
124 will add address to interface list by calling
125 connected_add_by_prefix()
127 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
131 pim_ifp
= c
->ifp
->info
;
134 if (PIM_DEBUG_ZEBRA
) {
136 prefix2str(p
, buf
, BUFSIZ
);
137 zlog_debug("%s: %s(%u) connected IP address %s flags %u %s",
138 __PRETTY_FUNCTION__
, c
->ifp
->name
, vrf_id
, buf
,
140 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)
144 #ifdef PIM_DEBUG_IFADDR_DUMP
145 dump_if_address(c
->ifp
);
149 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
150 /* trying to add primary address */
152 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
153 if (p
->family
!= AF_INET
154 || primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
155 if (PIM_DEBUG_ZEBRA
) {
156 /* but we had a primary address already */
160 prefix2str(p
, buf
, BUFSIZ
);
163 "%s: %s : forcing secondary flag on %s",
164 __PRETTY_FUNCTION__
, c
->ifp
->name
, buf
);
166 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
172 pim
= pim_get_pim_instance(vrf_id
);
175 pim_rp_check_on_if_add(pim_ifp
);
178 if (if_is_loopback(c
->ifp
)) {
179 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
180 struct interface
*ifp
;
182 FOR_ALL_INTERFACES (vrf
, ifp
) {
183 if (!if_is_loopback(ifp
) && if_is_operative(ifp
))
184 pim_if_addr_add_all(ifp
);
191 static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS
)
195 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
196 struct pim_instance
*pim
;
203 zebra api notifies address adds/dels events by using the same call
204 interface_add_read below, see comments in lib/zclient.c
206 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
207 will remove address from interface list by calling
208 connected_delete_by_prefix()
210 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
215 if (p
->family
== AF_INET
) {
216 if (PIM_DEBUG_ZEBRA
) {
218 prefix2str(p
, buf
, BUFSIZ
);
220 "%s: %s(%u) disconnected IP address %s flags %u %s",
221 __PRETTY_FUNCTION__
, c
->ifp
->name
, vrf_id
, buf
,
223 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)
227 #ifdef PIM_DEBUG_IFADDR_DUMP
228 dump_if_address(c
->ifp
);
232 pim_if_addr_del(c
, 0);
234 pim_i_am_rp_re_evaluate(pim
);
241 void pim_zebra_update_all_interfaces(struct pim_instance
*pim
)
243 struct interface
*ifp
;
245 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
246 struct pim_interface
*pim_ifp
= ifp
->info
;
247 struct pim_iface_upstream_switch
*us
;
248 struct listnode
*node
;
253 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->upstream_switch_list
, node
,
257 rpf
.source_nexthop
.interface
= ifp
;
258 rpf
.rpf_addr
.u
.prefix4
= us
->address
;
259 pim_joinprune_send(&rpf
, us
->us
);
260 pim_jp_agg_clear_group(us
->us
);
265 void pim_zebra_upstream_rpf_changed(struct pim_instance
*pim
,
266 struct pim_upstream
*up
,
269 if (old
->source_nexthop
.interface
) {
270 struct pim_neighbor
*nbr
;
272 nbr
= pim_neighbor_find(old
->source_nexthop
.interface
,
273 old
->rpf_addr
.u
.prefix4
);
275 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
, nbr
);
278 * We have detected a case where we might need
279 * to rescan the inherited o_list so do it.
281 if (up
->channel_oil
->oil_inherited_rescan
) {
282 pim_upstream_inherited_olist_decide(pim
, up
);
283 up
->channel_oil
->oil_inherited_rescan
= 0;
286 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
288 * If we come up real fast we can be here
289 * where the mroute has not been installed
292 if (!up
->channel_oil
->installed
)
293 pim_upstream_mroute_add(up
->channel_oil
,
294 __PRETTY_FUNCTION__
);
297 * RFC 4601: 4.5.7. Sending (S,G)
298 * Join/Prune Messages
300 * Transitions from Joined State
302 * RPF'(S,G) changes not due to an Assert
304 * The upstream (S,G) state machine remains
305 * in Joined state. Send Join(S,G) to the new
306 * upstream neighbor, which is the new value
307 * of RPF'(S,G). Send Prune(S,G) to the old
308 * upstream neighbor, which is the old value
309 * of RPF'(S,G). Set the Join Timer (JT) to
310 * expire after t_periodic seconds.
312 pim_jp_agg_switch_interface(old
, &up
->rpf
, up
);
314 pim_upstream_join_timer_restart(up
, old
);
315 } /* up->join_state == PIM_UPSTREAM_JOINED */
320 * We have detected a case where we might need
321 * to rescan the inherited o_list so do it.
323 if (up
->channel_oil
->oil_inherited_rescan
) {
324 pim_upstream_inherited_olist_decide(pim
, up
);
325 up
->channel_oil
->oil_inherited_rescan
= 0;
328 if (up
->join_state
== PIM_UPSTREAM_JOINED
)
329 pim_jp_agg_switch_interface(old
, &up
->rpf
, up
);
331 if (!up
->channel_oil
->installed
)
332 pim_upstream_mroute_add(up
->channel_oil
,
333 __PRETTY_FUNCTION__
);
336 /* FIXME can join_desired actually be changed by pim_rpf_update()
337 * returning PIM_RPF_CHANGED ?
339 pim_upstream_update_join_desired(pim
, up
);
342 static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS
)
345 struct pim_instance
*pim
;
348 pim
= pim_get_pim_instance(vrf_id
);
355 sg
.prefixlen
= stream_getl(s
);
356 stream_get(&sg
.src
.s_addr
, s
, sg
.prefixlen
);
357 stream_get(&sg
.grp
.s_addr
, s
, sg
.prefixlen
);
359 if (PIM_DEBUG_ZEBRA
) {
360 char sg_str
[PIM_SG_LEN
];
362 pim_str_sg_set(&sg
, sg_str
);
363 zlog_debug("%u:recv SG %s %s", vrf_id
,
364 (cmd
== ZEBRA_VXLAN_SG_ADD
)?"add":"del",
368 if (cmd
== ZEBRA_VXLAN_SG_ADD
)
369 pim_vxlan_sg_add(pim
, &sg
);
371 pim_vxlan_sg_del(pim
, &sg
);
376 static void pim_zebra_vxlan_replay(void)
378 struct stream
*s
= NULL
;
381 if (!zclient
|| zclient
->sock
< 0)
387 zclient_create_header(s
, ZEBRA_VXLAN_SG_REPLAY
, VRF_DEFAULT
);
388 stream_putw_at(s
, 0, stream_get_endp(s
));
390 zclient_send_message(zclient
);
393 void pim_scan_oil(struct pim_instance
*pim
)
395 struct listnode
*node
;
396 struct listnode
*nextnode
;
397 struct channel_oil
*c_oil
;
399 pim
->scan_oil_last
= pim_time_monotonic_sec();
400 ++pim
->scan_oil_events
;
402 for (ALL_LIST_ELEMENTS(pim
->channel_oil_list
, node
, nextnode
, c_oil
)) {
403 pim_upstream_mroute_iif_update(c_oil
, __func__
);
407 static int on_rpf_cache_refresh(struct thread
*t
)
409 struct pim_instance
*pim
= THREAD_ARG(t
);
411 /* update kernel multicast forwarding cache (MFC) */
414 pim
->rpf_cache_refresh_last
= pim_time_monotonic_sec();
415 ++pim
->rpf_cache_refresh_events
;
417 // It is called as part of pim_neighbor_add
422 void sched_rpf_cache_refresh(struct pim_instance
*pim
)
424 ++pim
->rpf_cache_refresh_requests
;
426 pim_rpf_set_refresh_time(pim
);
428 if (pim
->rpf_cache_refresher
) {
429 /* Refresh timer is already running */
433 /* Start refresh timer */
435 if (PIM_DEBUG_ZEBRA
) {
436 zlog_debug("%s: triggering %ld msec timer", __PRETTY_FUNCTION__
,
437 router
->rpf_cache_refresh_delay_msec
);
440 thread_add_timer_msec(router
->master
, on_rpf_cache_refresh
, pim
,
441 router
->rpf_cache_refresh_delay_msec
,
442 &pim
->rpf_cache_refresher
);
445 static void pim_zebra_connected(struct zclient
*zclient
)
447 /* Send the client registration */
448 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
, router
->vrf_id
);
450 zclient_send_reg_requests(zclient
, router
->vrf_id
);
452 /* request for VxLAN BUM group addresses */
453 pim_zebra_vxlan_replay();
456 static void pim_zebra_capabilities(struct zclient_capabilities
*cap
)
458 router
->role
= cap
->role
;
461 void pim_zebra_init(void)
463 /* Socket for receiving updates from Zebra daemon */
464 zclient
= zclient_new(router
->master
, &zclient_options_default
);
466 zclient
->zebra_capabilities
= pim_zebra_capabilities
;
467 zclient
->zebra_connected
= pim_zebra_connected
;
468 zclient
->router_id_update
= pim_router_id_update_zebra
;
469 zclient
->interface_address_add
= pim_zebra_if_address_add
;
470 zclient
->interface_address_delete
= pim_zebra_if_address_del
;
471 zclient
->interface_vrf_update
= pim_zebra_interface_vrf_update
;
472 zclient
->nexthop_update
= pim_parse_nexthop_update
;
473 zclient
->vxlan_sg_add
= pim_zebra_vxlan_sg_proc
;
474 zclient
->vxlan_sg_del
= pim_zebra_vxlan_sg_proc
;
475 zclient
->mlag_process_up
= pim_zebra_mlag_process_up
;
476 zclient
->mlag_process_down
= pim_zebra_mlag_process_down
;
477 zclient
->mlag_handle_msg
= pim_zebra_mlag_handle_msg
;
479 zclient_init(zclient
, ZEBRA_ROUTE_PIM
, 0, &pimd_privs
);
480 if (PIM_DEBUG_PIM_TRACE
) {
481 zlog_notice("%s: zclient socket initialized",
482 __PRETTY_FUNCTION__
);
485 zclient_lookup_new();
488 void igmp_anysource_forward_start(struct pim_instance
*pim
,
489 struct igmp_group
*group
)
491 struct igmp_source
*source
;
492 struct in_addr src_addr
= {.s_addr
= 0};
493 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
494 zassert(group
->group_filtermode_isexcl
);
495 zassert(listcount(group
->group_source_list
) < 1);
497 source
= source_new(group
, src_addr
);
499 zlog_warn("%s: Failure to create * source",
500 __PRETTY_FUNCTION__
);
504 igmp_source_forward_start(pim
, source
);
507 void igmp_anysource_forward_stop(struct igmp_group
*group
)
509 struct igmp_source
*source
;
510 struct in_addr star
= {.s_addr
= 0};
512 source
= igmp_find_source_by_addr(group
, star
);
514 igmp_source_forward_stop(source
);
517 static void igmp_source_forward_reevaluate_one(struct pim_instance
*pim
,
518 struct igmp_source
*source
)
521 struct igmp_group
*group
= source
->source_group
;
522 struct pim_ifchannel
*ch
;
524 if ((source
->source_addr
.s_addr
!= INADDR_ANY
)
525 || !IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
))
528 memset(&sg
, 0, sizeof(struct prefix_sg
));
529 sg
.src
= source
->source_addr
;
530 sg
.grp
= group
->group_addr
;
532 ch
= pim_ifchannel_find(group
->group_igmp_sock
->interface
, &sg
);
533 if (pim_is_grp_ssm(pim
, group
->group_addr
)) {
534 /* If SSM group withdraw local membership */
536 && (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_INCLUDE
)) {
537 if (PIM_DEBUG_PIM_EVENTS
)
539 "local membership del for %s as G is now SSM",
540 pim_str_sg_dump(&sg
));
541 pim_ifchannel_local_membership_del(
542 group
->group_igmp_sock
->interface
, &sg
);
545 /* If ASM group add local membership */
547 || (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_NOINFO
)) {
548 if (PIM_DEBUG_PIM_EVENTS
)
550 "local membership add for %s as G is now ASM",
551 pim_str_sg_dump(&sg
));
552 pim_ifchannel_local_membership_add(
553 group
->group_igmp_sock
->interface
, &sg
);
558 void igmp_source_forward_reevaluate_all(struct pim_instance
*pim
)
560 struct interface
*ifp
;
562 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
563 struct pim_interface
*pim_ifp
= ifp
->info
;
564 struct listnode
*sock_node
;
565 struct igmp_sock
*igmp
;
570 /* scan igmp sockets */
571 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->igmp_socket_list
, sock_node
,
573 struct listnode
*grpnode
;
574 struct igmp_group
*grp
;
576 /* scan igmp groups */
577 for (ALL_LIST_ELEMENTS_RO(igmp
->igmp_group_list
,
579 struct listnode
*srcnode
;
580 struct igmp_source
*src
;
582 /* scan group sources */
583 for (ALL_LIST_ELEMENTS_RO(
584 grp
->group_source_list
, srcnode
,
586 igmp_source_forward_reevaluate_one(pim
,
588 } /* scan group sources */
589 } /* scan igmp groups */
590 } /* scan igmp sockets */
591 } /* scan interfaces */
594 void igmp_source_forward_start(struct pim_instance
*pim
,
595 struct igmp_source
*source
)
597 struct pim_interface
*pim_oif
;
598 struct igmp_group
*group
;
601 int input_iface_vif_index
= 0;
603 memset(&sg
, 0, sizeof(struct prefix_sg
));
604 sg
.src
= source
->source_addr
;
605 sg
.grp
= source
->source_group
->group_addr
;
607 if (PIM_DEBUG_IGMP_TRACE
) {
609 "%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
610 __PRETTY_FUNCTION__
, pim_str_sg_dump(&sg
),
611 source
->source_group
->group_igmp_sock
->fd
,
612 source
->source_group
->group_igmp_sock
->interface
->name
,
613 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
616 /* Prevent IGMP interface from installing multicast route multiple
618 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
622 group
= source
->source_group
;
623 pim_oif
= group
->group_igmp_sock
->interface
->info
;
625 if (PIM_DEBUG_IGMP_TRACE
) {
627 "%s: multicast not enabled on oif=%s ?",
629 source
->source_group
->group_igmp_sock
635 if (!source
->source_channel_oil
) {
636 struct in_addr vif_source
;
637 struct prefix src
, grp
;
638 struct pim_nexthop nexthop
;
639 struct pim_upstream
*up
= NULL
;
641 if (!pim_rp_set_upstream_addr(pim
, &vif_source
,
642 source
->source_addr
, sg
.grp
)) {
643 /*Create a dummy channel oil */
644 source
->source_channel_oil
= pim_channel_oil_add(
645 pim
, &sg
, __PRETTY_FUNCTION__
);
649 src
.family
= AF_INET
;
650 src
.prefixlen
= IPV4_MAX_BITLEN
;
651 src
.u
.prefix4
= vif_source
; // RP or Src address
652 grp
.family
= AF_INET
;
653 grp
.prefixlen
= IPV4_MAX_BITLEN
;
654 grp
.u
.prefix4
= sg
.grp
;
656 up
= pim_upstream_find(pim
, &sg
);
658 memcpy(&nexthop
, &up
->rpf
.source_nexthop
,
659 sizeof(struct pim_nexthop
));
660 pim_ecmp_nexthop_lookup(pim
, &nexthop
, &src
,
662 if (nexthop
.interface
)
663 input_iface_vif_index
=
664 pim_if_find_vifindex_by_ifindex(
666 nexthop
.interface
->ifindex
);
668 input_iface_vif_index
=
669 pim_ecmp_fib_lookup_if_vif_index(
672 if (PIM_DEBUG_ZEBRA
) {
673 char buf2
[INET_ADDRSTRLEN
];
675 pim_inet4_dump("<source?>", vif_source
, buf2
,
677 zlog_debug("%s: NHT %s vif_source %s vif_index:%d ",
679 pim_str_sg_dump(&sg
),
680 buf2
, input_iface_vif_index
);
683 if (input_iface_vif_index
< 1) {
684 if (PIM_DEBUG_IGMP_TRACE
) {
685 char source_str
[INET_ADDRSTRLEN
];
686 pim_inet4_dump("<source?>",
688 source_str
, sizeof(source_str
));
690 "%s %s: could not find input interface for source %s",
691 __FILE__
, __PRETTY_FUNCTION__
,
694 source
->source_channel_oil
=
697 __PRETTY_FUNCTION__
);
702 * Protect IGMP against adding looped MFC
703 * entries created by both source and receiver
704 * attached to the same interface. See TODO
705 * T22. Block only when the intf is non DR
706 * DR must create upstream.
708 if ((input_iface_vif_index
==
709 pim_oif
->mroute_vif_index
) &&
710 !(PIM_I_am_DR(pim_oif
))) {
711 /* ignore request for looped MFC entry
713 if (PIM_DEBUG_IGMP_TRACE
) {
715 "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
717 pim_str_sg_dump(&sg
),
719 ->group_igmp_sock
->fd
,
723 input_iface_vif_index
);
728 source
->source_channel_oil
=
731 __PRETTY_FUNCTION__
);
732 if (!source
->source_channel_oil
) {
733 if (PIM_DEBUG_IGMP_TRACE
) {
735 "%s %s: could not create OIL for channel (S,G)=%s",
738 pim_str_sg_dump(&sg
));
746 if (PIM_I_am_DR(pim_oif
)) {
747 result
= pim_channel_add_oif(source
->source_channel_oil
,
748 group
->group_igmp_sock
->interface
,
749 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
751 if (PIM_DEBUG_MROUTE
) {
752 zlog_warn("%s: add_oif() failed with return=%d",
758 if (PIM_DEBUG_IGMP_TRACE
)
759 zlog_debug("%s: %s was received on %s interface but we are not DR for that interface",
761 pim_str_sg_dump(&sg
),
762 group
->group_igmp_sock
->interface
->name
);
767 Feed IGMPv3-gathered local membership information into PIM
768 per-interface (S,G) state.
770 if (!pim_ifchannel_local_membership_add(
771 group
->group_igmp_sock
->interface
, &sg
)) {
772 if (PIM_DEBUG_MROUTE
)
773 zlog_warn("%s: Failure to add local membership for %s",
774 __PRETTY_FUNCTION__
, pim_str_sg_dump(&sg
));
776 pim_channel_del_oif(source
->source_channel_oil
,
777 group
->group_igmp_sock
->interface
,
778 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
782 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
786 igmp_source_forward_stop: stop fowarding, but keep the source
787 igmp_source_delete: stop fowarding, and delete the source
789 void igmp_source_forward_stop(struct igmp_source
*source
)
791 struct igmp_group
*group
;
795 memset(&sg
, 0, sizeof(struct prefix_sg
));
796 sg
.src
= source
->source_addr
;
797 sg
.grp
= source
->source_group
->group_addr
;
799 if (PIM_DEBUG_IGMP_TRACE
) {
801 "%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
802 __PRETTY_FUNCTION__
, pim_str_sg_dump(&sg
),
803 source
->source_group
->group_igmp_sock
->fd
,
804 source
->source_group
->group_igmp_sock
->interface
->name
,
805 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
808 /* Prevent IGMP interface from removing multicast route multiple
810 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
814 group
= source
->source_group
;
817 It appears that in certain circumstances that
818 igmp_source_forward_stop is called when IGMP forwarding
819 was not enabled in oif_flags for this outgoing interface.
820 Possibly because of multiple calls. When that happens, we
821 enter the below if statement and this function returns early
822 which in turn triggers the calling function to assert.
823 Making the call to pim_channel_del_oif and ignoring the return code
824 fixes the issue without ill effect, similar to
825 pim_forward_stop below.
827 result
= pim_channel_del_oif(source
->source_channel_oil
,
828 group
->group_igmp_sock
->interface
,
829 PIM_OIF_FLAG_PROTO_IGMP
,
832 if (PIM_DEBUG_IGMP_TRACE
)
834 "%s: pim_channel_del_oif() failed with return=%d",
840 Feed IGMPv3-gathered local membership information into PIM
841 per-interface (S,G) state.
843 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
846 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
849 void pim_forward_start(struct pim_ifchannel
*ch
)
851 struct pim_upstream
*up
= ch
->upstream
;
852 uint32_t mask
= PIM_OIF_FLAG_PROTO_PIM
;
854 if (PIM_DEBUG_PIM_TRACE
) {
855 char source_str
[INET_ADDRSTRLEN
];
856 char group_str
[INET_ADDRSTRLEN
];
857 char upstream_str
[INET_ADDRSTRLEN
];
859 pim_inet4_dump("<source?>", ch
->sg
.src
, source_str
,
861 pim_inet4_dump("<group?>", ch
->sg
.grp
, group_str
,
863 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
,
864 sizeof(upstream_str
));
865 zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__
,
866 source_str
, group_str
, ch
->interface
->name
,
867 inet_ntoa(up
->upstream_addr
));
870 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_IGMP
)
871 mask
= PIM_OIF_FLAG_PROTO_IGMP
;
873 pim_channel_add_oif(up
->channel_oil
, ch
->interface
,
877 void pim_forward_stop(struct pim_ifchannel
*ch
, bool install_it
)
879 struct pim_upstream
*up
= ch
->upstream
;
881 if (PIM_DEBUG_PIM_TRACE
) {
882 zlog_debug("%s: (S,G)=%s oif=%s install_it: %d installed: %d",
883 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->interface
->name
,
884 install_it
, up
->channel_oil
->installed
);
888 * If a channel is being removed, check to see if we still need
889 * to inherit the interface. If so make sure it is added in
891 if (pim_upstream_evaluate_join_desired_interface(up
, ch
, ch
->parent
))
892 pim_channel_add_oif(up
->channel_oil
, ch
->interface
,
893 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
895 pim_channel_del_oif(up
->channel_oil
, ch
->interface
,
896 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
898 if (install_it
&& !up
->channel_oil
->installed
)
899 pim_upstream_mroute_add(up
->channel_oil
, __PRETTY_FUNCTION__
);
902 void pim_zebra_zclient_update(struct vty
*vty
)
904 vty_out(vty
, "Zclient update socket: ");
907 vty_out(vty
, "%d failures=%d\n", zclient
->sock
, zclient
->fail
);
909 vty_out(vty
, "<null zclient>\n");
913 struct zclient
*pim_zebra_zclient_get(void)
921 void pim_zebra_interface_set_master(struct interface
*vrf
,
922 struct interface
*ifp
)
924 zclient_interface_set_master(zclient
, vrf
, ifp
);