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 __attribute__((unused
))
59 static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS
)
61 struct prefix router_id
;
63 zebra_router_id_update_read(zclient
->ibuf
, &router_id
);
68 __attribute__((unused
))
69 static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS
)
71 struct interface
*ifp
;
74 ifp
= zebra_interface_vrf_update_read(zclient
->ibuf
, vrf_id
,
80 zlog_debug("%s: %s updating from %u to %u", __func__
, ifp
->name
,
83 if_update_to_new_vrf(ifp
, new_vrf_id
);
88 #ifdef PIM_DEBUG_IFADDR_DUMP
89 static void dump_if_address(struct interface
*ifp
)
91 struct connected
*ifc
;
92 struct listnode
*node
;
94 zlog_debug("%s %s: interface %s addresses:", __FILE__
, __func__
,
97 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
98 struct prefix
*p
= ifc
->address
;
100 if (p
->family
!= AF_INET
)
103 zlog_debug("%s %s: interface %s address %pI4 %s", __FILE__
,
104 __func__
, ifp
->name
, &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
;
119 zebra api notifies address adds/dels events by using the same call
120 interface_add_read below, see comments in lib/zclient.c
122 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
123 will add address to interface list by calling
124 connected_add_by_prefix()
126 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
130 pim_ifp
= c
->ifp
->info
;
133 if (PIM_DEBUG_ZEBRA
) {
134 zlog_debug("%s: %s(%u) connected IP address %pFX flags %u %s",
135 __func__
, c
->ifp
->name
, vrf_id
, p
, c
->flags
,
136 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)
140 #ifdef PIM_DEBUG_IFADDR_DUMP
141 dump_if_address(c
->ifp
);
146 if (p
->family
!= PIM_AF
)
147 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
148 else if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
149 /* trying to add primary address? */
150 pim_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
151 pim_addr addr
= pim_addr_from_prefix(p
);
153 if (pim_addr_cmp(primary_addr
, addr
)) {
156 "%s: %s : forcing secondary flag on %pFX",
157 __func__
, c
->ifp
->name
, p
);
158 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
164 struct pim_instance
*pim
;
166 pim
= pim_get_pim_instance(vrf_id
);
169 pim_rp_check_on_if_add(pim_ifp
);
172 if (if_is_loopback(c
->ifp
)) {
173 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
174 struct interface
*ifp
;
176 FOR_ALL_INTERFACES (vrf
, ifp
) {
177 if (!if_is_loopback(ifp
) && if_is_operative(ifp
))
178 pim_if_addr_add_all(ifp
);
181 #else /* PIM_IPV != 4 */
182 /* unused - for now */
188 static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS
)
192 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
198 zebra api notifies address adds/dels events by using the same call
199 interface_add_read below, see comments in lib/zclient.c
201 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
202 will remove address from interface list by calling
203 connected_delete_by_prefix()
205 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
211 if (PIM_DEBUG_ZEBRA
) {
213 "%s: %s(%u) disconnected IP address %pFX flags %u %s",
214 __func__
, c
->ifp
->name
, vrf_id
, p
, c
->flags
,
215 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)
218 #ifdef PIM_DEBUG_IFADDR_DUMP
219 dump_if_address(c
->ifp
);
224 if (p
->family
== AF_INET
) {
225 struct pim_instance
*pim
;
228 pim_if_addr_del(c
, 0);
230 pim_i_am_rp_re_evaluate(pim
);
238 void pim_zebra_update_all_interfaces(struct pim_instance
*pim
)
240 struct interface
*ifp
;
242 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
243 struct pim_interface
*pim_ifp
= ifp
->info
;
244 struct pim_iface_upstream_switch
*us
;
245 struct listnode
*node
;
250 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->upstream_switch_list
, node
,
254 rpf
.source_nexthop
.interface
= ifp
;
255 pim_addr_to_prefix(&rpf
.rpf_addr
, us
->address
);
256 pim_joinprune_send(&rpf
, us
->us
);
257 pim_jp_agg_clear_group(us
->us
);
262 void pim_zebra_upstream_rpf_changed(struct pim_instance
*pim
,
263 struct pim_upstream
*up
,
266 if (old
->source_nexthop
.interface
) {
267 struct pim_neighbor
*nbr
;
269 nbr
= pim_neighbor_find_prefix(old
->source_nexthop
.interface
,
272 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
, nbr
);
275 * We have detected a case where we might need
276 * to rescan the inherited o_list so do it.
278 if (up
->channel_oil
->oil_inherited_rescan
) {
279 pim_upstream_inherited_olist_decide(pim
, up
);
280 up
->channel_oil
->oil_inherited_rescan
= 0;
283 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
285 * If we come up real fast we can be here
286 * where the mroute has not been installed
289 if (!up
->channel_oil
->installed
)
290 pim_upstream_mroute_add(up
->channel_oil
,
294 * RFC 4601: 4.5.7. Sending (S,G)
295 * Join/Prune Messages
297 * Transitions from Joined State
299 * RPF'(S,G) changes not due to an Assert
301 * The upstream (S,G) state machine remains
302 * in Joined state. Send Join(S,G) to the new
303 * upstream neighbor, which is the new value
304 * of RPF'(S,G). Send Prune(S,G) to the old
305 * upstream neighbor, which is the old value
306 * of RPF'(S,G). Set the Join Timer (JT) to
307 * expire after t_periodic seconds.
309 pim_jp_agg_switch_interface(old
, &up
->rpf
, up
);
311 pim_upstream_join_timer_restart(up
, old
);
312 } /* up->join_state == PIM_UPSTREAM_JOINED */
317 * We have detected a case where we might need
318 * to rescan the inherited o_list so do it.
320 if (up
->channel_oil
->oil_inherited_rescan
) {
321 pim_upstream_inherited_olist_decide(pim
, up
);
322 up
->channel_oil
->oil_inherited_rescan
= 0;
325 if (up
->join_state
== PIM_UPSTREAM_JOINED
)
326 pim_jp_agg_switch_interface(old
, &up
->rpf
, up
);
328 if (!up
->channel_oil
->installed
)
329 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
332 /* FIXME can join_desired actually be changed by pim_rpf_update()
333 * returning PIM_RPF_CHANGED ?
335 pim_upstream_update_join_desired(pim
, up
);
338 __attribute__((unused
))
339 static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS
)
342 struct pim_instance
*pim
;
346 pim
= pim_get_pim_instance(vrf_id
);
352 prefixlen
= stream_getl(s
);
353 stream_get(&sg
.src
, s
, prefixlen
);
354 stream_get(&sg
.grp
, s
, prefixlen
);
357 zlog_debug("%u:recv SG %s %pSG", vrf_id
,
358 (cmd
== ZEBRA_VXLAN_SG_ADD
) ? "add" : "del", &sg
);
360 if (cmd
== ZEBRA_VXLAN_SG_ADD
)
361 pim_vxlan_sg_add(pim
, &sg
);
363 pim_vxlan_sg_del(pim
, &sg
);
368 __attribute__((unused
))
369 static void pim_zebra_vxlan_replay(void)
371 struct stream
*s
= NULL
;
374 if (!zclient
|| zclient
->sock
< 0)
380 zclient_create_header(s
, ZEBRA_VXLAN_SG_REPLAY
, VRF_DEFAULT
);
381 stream_putw_at(s
, 0, stream_get_endp(s
));
383 zclient_send_message(zclient
);
386 void pim_scan_oil(struct pim_instance
*pim
)
388 struct channel_oil
*c_oil
;
390 pim
->scan_oil_last
= pim_time_monotonic_sec();
391 ++pim
->scan_oil_events
;
393 frr_each (rb_pim_oil
, &pim
->channel_oil_head
, c_oil
)
394 pim_upstream_mroute_iif_update(c_oil
, __func__
);
397 static void on_rpf_cache_refresh(struct thread
*t
)
399 struct pim_instance
*pim
= THREAD_ARG(t
);
401 /* update kernel multicast forwarding cache (MFC) */
404 pim
->rpf_cache_refresh_last
= pim_time_monotonic_sec();
405 ++pim
->rpf_cache_refresh_events
;
407 // It is called as part of pim_neighbor_add
411 void sched_rpf_cache_refresh(struct pim_instance
*pim
)
413 ++pim
->rpf_cache_refresh_requests
;
415 pim_rpf_set_refresh_time(pim
);
417 if (pim
->rpf_cache_refresher
) {
418 /* Refresh timer is already running */
422 /* Start refresh timer */
424 if (PIM_DEBUG_ZEBRA
) {
425 zlog_debug("%s: triggering %ld msec timer", __func__
,
426 router
->rpf_cache_refresh_delay_msec
);
429 thread_add_timer_msec(router
->master
, on_rpf_cache_refresh
, pim
,
430 router
->rpf_cache_refresh_delay_msec
,
431 &pim
->rpf_cache_refresher
);
434 static void pim_zebra_connected(struct zclient
*zclient
)
437 /* Send the client registration */
438 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
, router
->vrf_id
);
441 zclient_send_reg_requests(zclient
, router
->vrf_id
);
444 /* request for VxLAN BUM group addresses */
445 pim_zebra_vxlan_replay();
449 static void pim_zebra_capabilities(struct zclient_capabilities
*cap
)
451 router
->mlag_role
= cap
->role
;
454 static zclient_handler
*const pim_handlers
[] = {
455 [ZEBRA_INTERFACE_ADDRESS_ADD
] = pim_zebra_if_address_add
,
456 [ZEBRA_INTERFACE_ADDRESS_DELETE
] = pim_zebra_if_address_del
,
458 [ZEBRA_NEXTHOP_UPDATE
] = pim_parse_nexthop_update
,
460 [ZEBRA_ROUTER_ID_UPDATE
] = pim_router_id_update_zebra
,
461 [ZEBRA_INTERFACE_VRF_UPDATE
] = pim_zebra_interface_vrf_update
,
463 [ZEBRA_VXLAN_SG_ADD
] = pim_zebra_vxlan_sg_proc
,
464 [ZEBRA_VXLAN_SG_DEL
] = pim_zebra_vxlan_sg_proc
,
466 [ZEBRA_MLAG_PROCESS_UP
] = pim_zebra_mlag_process_up
,
467 [ZEBRA_MLAG_PROCESS_DOWN
] = pim_zebra_mlag_process_down
,
468 [ZEBRA_MLAG_FORWARD_MSG
] = pim_zebra_mlag_handle_msg
,
472 void pim_zebra_init(void)
474 /* Socket for receiving updates from Zebra daemon */
475 zclient
= zclient_new(router
->master
, &zclient_options_default
,
476 pim_handlers
, array_size(pim_handlers
));
478 zclient
->zebra_capabilities
= pim_zebra_capabilities
;
479 zclient
->zebra_connected
= pim_zebra_connected
;
481 zclient_init(zclient
, ZEBRA_ROUTE_PIM
, 0, &pimd_privs
);
482 if (PIM_DEBUG_PIM_TRACE
) {
483 zlog_notice("%s: zclient socket initialized", __func__
);
486 zclient_lookup_new();
490 void igmp_anysource_forward_start(struct pim_instance
*pim
,
491 struct gm_group
*group
)
493 struct gm_source
*source
;
494 struct in_addr src_addr
= {.s_addr
= 0};
495 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
496 assert(group
->group_filtermode_isexcl
);
497 assert(listcount(group
->group_source_list
) < 1);
499 source
= igmp_get_source_by_addr(group
, src_addr
, NULL
);
501 zlog_warn("%s: Failure to create * source", __func__
);
505 igmp_source_forward_start(pim
, source
);
508 void igmp_anysource_forward_stop(struct gm_group
*group
)
510 struct gm_source
*source
;
511 struct in_addr star
= {.s_addr
= 0};
513 source
= igmp_find_source_by_addr(group
, star
);
515 igmp_source_forward_stop(source
);
518 static void igmp_source_forward_reevaluate_one(struct pim_instance
*pim
,
519 struct gm_source
*source
)
522 struct gm_group
*group
= source
->source_group
;
523 struct pim_ifchannel
*ch
;
525 if ((source
->source_addr
.s_addr
!= INADDR_ANY
)
526 || !IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
))
529 memset(&sg
, 0, sizeof(sg
));
530 sg
.src
= source
->source_addr
;
531 sg
.grp
= group
->group_addr
;
533 ch
= pim_ifchannel_find(group
->interface
, &sg
);
534 if (pim_is_grp_ssm(pim
, group
->group_addr
)) {
535 /* If SSM group withdraw local membership */
537 && (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_INCLUDE
)) {
538 if (PIM_DEBUG_PIM_EVENTS
)
539 zlog_debug("local membership del for %pSG as G is now SSM",
541 pim_ifchannel_local_membership_del(group
->interface
,
545 /* If ASM group add local membership */
547 || (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_NOINFO
)) {
548 if (PIM_DEBUG_PIM_EVENTS
)
549 zlog_debug("local membership add for %pSG as G is now ASM",
551 pim_ifchannel_local_membership_add(
552 group
->interface
, &sg
, false /*is_vxlan*/);
557 void igmp_source_forward_reevaluate_all(struct pim_instance
*pim
)
559 struct interface
*ifp
;
561 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
562 struct pim_interface
*pim_ifp
= ifp
->info
;
563 struct listnode
*grpnode
;
564 struct gm_group
*grp
;
565 struct pim_ifchannel
*ch
, *ch_temp
;
570 /* scan igmp groups */
571 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->gm_group_list
, grpnode
,
573 struct listnode
*srcnode
;
574 struct gm_source
*src
;
576 /* scan group sources */
577 for (ALL_LIST_ELEMENTS_RO(grp
->group_source_list
,
579 igmp_source_forward_reevaluate_one(pim
, src
);
580 } /* scan group sources */
581 } /* scan igmp groups */
583 RB_FOREACH_SAFE (ch
, pim_ifchannel_rb
, &pim_ifp
->ifchannel_rb
,
585 if (pim_is_grp_ssm(pim
, ch
->sg
.grp
)) {
586 if (pim_addr_is_any(ch
->sg
.src
))
587 pim_ifchannel_delete(ch
);
590 } /* scan interfaces */
593 void igmp_source_forward_start(struct pim_instance
*pim
,
594 struct gm_source
*source
)
596 struct pim_interface
*pim_oif
;
597 struct gm_group
*group
;
600 int input_iface_vif_index
= 0;
602 memset(&sg
, 0, sizeof(sg
));
603 sg
.src
= source
->source_addr
;
604 sg
.grp
= source
->source_group
->group_addr
;
606 if (PIM_DEBUG_IGMP_TRACE
) {
607 zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__
, &sg
,
608 source
->source_group
->interface
->name
,
609 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
612 /* Prevent IGMP interface from installing multicast route multiple
614 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
618 group
= source
->source_group
;
619 pim_oif
= group
->interface
->info
;
621 if (PIM_DEBUG_IGMP_TRACE
) {
622 zlog_debug("%s: multicast not enabled on oif=%s ?",
624 source
->source_group
->interface
->name
);
629 if (!source
->source_channel_oil
) {
631 struct prefix src
, grp
;
632 struct pim_nexthop nexthop
;
633 struct pim_upstream
*up
= NULL
;
635 if (!pim_rp_set_upstream_addr(pim
, &vif_source
,
636 source
->source_addr
, sg
.grp
)) {
637 /*Create a dummy channel oil */
638 source
->source_channel_oil
=
639 pim_channel_oil_add(pim
, &sg
, __func__
);
643 pim_addr_to_prefix(&src
, vif_source
); // RP or Src addr
644 pim_addr_to_prefix(&grp
, sg
.grp
);
646 up
= pim_upstream_find(pim
, &sg
);
648 memcpy(&nexthop
, &up
->rpf
.source_nexthop
,
649 sizeof(struct pim_nexthop
));
650 pim_ecmp_nexthop_lookup(pim
, &nexthop
, &src
,
652 if (nexthop
.interface
)
653 input_iface_vif_index
=
654 pim_if_find_vifindex_by_ifindex(
656 nexthop
.interface
->ifindex
);
658 input_iface_vif_index
=
659 pim_ecmp_fib_lookup_if_vif_index(
664 "%s: NHT %pSG vif_source %pPAs vif_index:%d ",
665 __func__
, &sg
, &vif_source
,
666 input_iface_vif_index
);
668 if (input_iface_vif_index
< 1) {
669 if (PIM_DEBUG_IGMP_TRACE
) {
670 char source_str
[INET_ADDRSTRLEN
];
671 pim_inet4_dump("<source?>",
673 source_str
, sizeof(source_str
));
675 "%s %s: could not find input interface for source %s",
676 __FILE__
, __func__
, source_str
);
678 source
->source_channel_oil
=
679 pim_channel_oil_add(pim
, &sg
, __func__
);
684 * Protect IGMP against adding looped MFC
685 * entries created by both source and receiver
686 * attached to the same interface. See TODO
687 * T22. Block only when the intf is non DR
688 * DR must create upstream.
690 if ((input_iface_vif_index
==
691 pim_oif
->mroute_vif_index
) &&
692 !(PIM_I_am_DR(pim_oif
))) {
693 /* ignore request for looped MFC entry
695 if (PIM_DEBUG_IGMP_TRACE
) {
696 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
701 input_iface_vif_index
);
706 source
->source_channel_oil
=
707 pim_channel_oil_add(pim
, &sg
, __func__
);
708 if (!source
->source_channel_oil
) {
709 if (PIM_DEBUG_IGMP_TRACE
) {
710 zlog_debug("%s %s: could not create OIL for channel (S,G)=%pSG",
720 if (PIM_I_am_DR(pim_oif
) || PIM_I_am_DualActive(pim_oif
)) {
721 result
= pim_channel_add_oif(source
->source_channel_oil
,
723 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
725 if (PIM_DEBUG_MROUTE
) {
726 zlog_warn("%s: add_oif() failed with return=%d",
732 if (PIM_DEBUG_IGMP_TRACE
)
733 zlog_debug("%s: %pSG was received on %s interface but we are not DR for that interface",
735 group
->interface
->name
);
740 Feed IGMPv3-gathered local membership information into PIM
741 per-interface (S,G) state.
743 if (!pim_ifchannel_local_membership_add(group
->interface
, &sg
,
744 false /*is_vxlan*/)) {
745 if (PIM_DEBUG_MROUTE
)
746 zlog_warn("%s: Failure to add local membership for %pSG",
749 pim_channel_del_oif(source
->source_channel_oil
,
750 group
->interface
, PIM_OIF_FLAG_PROTO_IGMP
,
755 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
759 igmp_source_forward_stop: stop fowarding, but keep the source
760 igmp_source_delete: stop fowarding, and delete the source
762 void igmp_source_forward_stop(struct gm_source
*source
)
764 struct gm_group
*group
;
768 memset(&sg
, 0, sizeof(sg
));
769 sg
.src
= source
->source_addr
;
770 sg
.grp
= source
->source_group
->group_addr
;
772 if (PIM_DEBUG_IGMP_TRACE
) {
773 zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__
, &sg
,
774 source
->source_group
->interface
->name
,
775 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
778 /* Prevent IGMP interface from removing multicast route multiple
780 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
784 group
= source
->source_group
;
787 It appears that in certain circumstances that
788 igmp_source_forward_stop is called when IGMP forwarding
789 was not enabled in oif_flags for this outgoing interface.
790 Possibly because of multiple calls. When that happens, we
791 enter the below if statement and this function returns early
792 which in turn triggers the calling function to assert.
793 Making the call to pim_channel_del_oif and ignoring the return code
794 fixes the issue without ill effect, similar to
795 pim_forward_stop below.
797 result
= pim_channel_del_oif(source
->source_channel_oil
,
798 group
->interface
, PIM_OIF_FLAG_PROTO_IGMP
,
801 if (PIM_DEBUG_IGMP_TRACE
)
803 "%s: pim_channel_del_oif() failed with return=%d",
809 Feed IGMPv3-gathered local membership information into PIM
810 per-interface (S,G) state.
812 pim_ifchannel_local_membership_del(group
->interface
, &sg
);
814 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
816 #endif /* PIM_IPV == 4 */
818 void pim_forward_start(struct pim_ifchannel
*ch
)
820 struct pim_upstream
*up
= ch
->upstream
;
823 if (PIM_DEBUG_PIM_TRACE
)
824 zlog_debug("%s: (S,G)=%pSG oif=%s (%pPA)", __func__
, &ch
->sg
,
825 ch
->interface
->name
, &up
->upstream_addr
);
827 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch
->flags
))
828 mask
= PIM_OIF_FLAG_PROTO_IGMP
;
830 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch
->flags
))
831 mask
|= PIM_OIF_FLAG_PROTO_PIM
;
833 pim_channel_add_oif(up
->channel_oil
, ch
->interface
,
837 void pim_forward_stop(struct pim_ifchannel
*ch
)
839 struct pim_upstream
*up
= ch
->upstream
;
841 if (PIM_DEBUG_PIM_TRACE
) {
842 zlog_debug("%s: (S,G)=%s oif=%s installed: %d",
843 __func__
, ch
->sg_str
, ch
->interface
->name
,
844 up
->channel_oil
->installed
);
848 * If a channel is being removed, check to see if we still need
849 * to inherit the interface. If so make sure it is added in
851 if (pim_upstream_evaluate_join_desired_interface(up
, ch
, ch
->parent
))
852 pim_channel_add_oif(up
->channel_oil
, ch
->interface
,
853 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
855 pim_channel_del_oif(up
->channel_oil
, ch
->interface
,
856 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
859 void pim_zebra_zclient_update(struct vty
*vty
)
861 vty_out(vty
, "Zclient update socket: ");
864 vty_out(vty
, "%d failures=%d\n", zclient
->sock
, zclient
->fail
);
866 vty_out(vty
, "<null zclient>\n");
870 struct zclient
*pim_zebra_zclient_get(void)
878 void pim_zebra_interface_set_master(struct interface
*vrf
,
879 struct interface
*ifp
)
881 zclient_interface_set_master(zclient
, vrf
, ifp
);