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", __func__
, ifp
->name
,
81 if_update_to_new_vrf(ifp
, new_vrf_id
);
86 #ifdef PIM_DEBUG_IFADDR_DUMP
87 static void dump_if_address(struct interface
*ifp
)
89 struct connected
*ifc
;
90 struct listnode
*node
;
92 zlog_debug("%s %s: interface %s addresses:", __FILE__
, __func__
,
95 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
96 struct prefix
*p
= ifc
->address
;
98 if (p
->family
!= AF_INET
)
101 zlog_debug("%s %s: interface %s address %pI4 %s", __FILE__
,
102 __func__
, ifp
->name
, &p
->u
.prefix4
,
103 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
110 static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS
)
114 struct pim_interface
*pim_ifp
;
115 struct pim_instance
*pim
;
118 zebra api notifies address adds/dels events by using the same call
119 interface_add_read below, see comments in lib/zclient.c
121 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
122 will add address to interface list by calling
123 connected_add_by_prefix()
125 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
129 pim_ifp
= c
->ifp
->info
;
132 if (PIM_DEBUG_ZEBRA
) {
133 zlog_debug("%s: %s(%u) connected IP address %pFX flags %u %s",
134 __func__
, c
->ifp
->name
, vrf_id
, p
, c
->flags
,
135 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)
139 #ifdef PIM_DEBUG_IFADDR_DUMP
140 dump_if_address(c
->ifp
);
144 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
145 /* trying to add primary address */
147 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
148 if (p
->family
!= AF_INET
149 || primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
152 "%s: %s : forcing secondary flag on %pFX",
153 __func__
, c
->ifp
->name
, p
);
154 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
160 pim
= pim_get_pim_instance(vrf_id
);
163 pim_rp_check_on_if_add(pim_ifp
);
166 if (if_is_loopback(c
->ifp
)) {
167 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
168 struct interface
*ifp
;
170 FOR_ALL_INTERFACES (vrf
, ifp
) {
171 if (!if_is_loopback(ifp
) && if_is_operative(ifp
))
172 pim_if_addr_add_all(ifp
);
179 static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS
)
183 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
184 struct pim_instance
*pim
;
191 zebra api notifies address adds/dels events by using the same call
192 interface_add_read below, see comments in lib/zclient.c
194 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
195 will remove address from interface list by calling
196 connected_delete_by_prefix()
198 c
= zebra_interface_address_read(cmd
, zclient
->ibuf
, vrf_id
);
203 if (p
->family
== AF_INET
) {
204 if (PIM_DEBUG_ZEBRA
) {
206 "%s: %s(%u) disconnected IP address %pFX flags %u %s",
207 __func__
, c
->ifp
->name
, vrf_id
, p
, c
->flags
,
208 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)
212 #ifdef PIM_DEBUG_IFADDR_DUMP
213 dump_if_address(c
->ifp
);
217 pim_if_addr_del(c
, 0);
219 pim_i_am_rp_re_evaluate(pim
);
226 void pim_zebra_update_all_interfaces(struct pim_instance
*pim
)
228 struct interface
*ifp
;
230 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
231 struct pim_interface
*pim_ifp
= ifp
->info
;
232 struct pim_iface_upstream_switch
*us
;
233 struct listnode
*node
;
238 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->upstream_switch_list
, node
,
242 rpf
.source_nexthop
.interface
= ifp
;
243 rpf
.rpf_addr
.u
.prefix4
= us
->address
;
244 pim_joinprune_send(&rpf
, us
->us
);
245 pim_jp_agg_clear_group(us
->us
);
250 void pim_zebra_upstream_rpf_changed(struct pim_instance
*pim
,
251 struct pim_upstream
*up
,
254 if (old
->source_nexthop
.interface
) {
255 struct pim_neighbor
*nbr
;
257 nbr
= pim_neighbor_find(old
->source_nexthop
.interface
,
258 old
->rpf_addr
.u
.prefix4
);
260 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
, up
, nbr
);
263 * We have detected a case where we might need
264 * to rescan the inherited o_list so do it.
266 if (up
->channel_oil
->oil_inherited_rescan
) {
267 pim_upstream_inherited_olist_decide(pim
, up
);
268 up
->channel_oil
->oil_inherited_rescan
= 0;
271 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
273 * If we come up real fast we can be here
274 * where the mroute has not been installed
277 if (!up
->channel_oil
->installed
)
278 pim_upstream_mroute_add(up
->channel_oil
,
282 * RFC 4601: 4.5.7. Sending (S,G)
283 * Join/Prune Messages
285 * Transitions from Joined State
287 * RPF'(S,G) changes not due to an Assert
289 * The upstream (S,G) state machine remains
290 * in Joined state. Send Join(S,G) to the new
291 * upstream neighbor, which is the new value
292 * of RPF'(S,G). Send Prune(S,G) to the old
293 * upstream neighbor, which is the old value
294 * of RPF'(S,G). Set the Join Timer (JT) to
295 * expire after t_periodic seconds.
297 pim_jp_agg_switch_interface(old
, &up
->rpf
, up
);
299 pim_upstream_join_timer_restart(up
, old
);
300 } /* up->join_state == PIM_UPSTREAM_JOINED */
305 * We have detected a case where we might need
306 * to rescan the inherited o_list so do it.
308 if (up
->channel_oil
->oil_inherited_rescan
) {
309 pim_upstream_inherited_olist_decide(pim
, up
);
310 up
->channel_oil
->oil_inherited_rescan
= 0;
313 if (up
->join_state
== PIM_UPSTREAM_JOINED
)
314 pim_jp_agg_switch_interface(old
, &up
->rpf
, up
);
316 if (!up
->channel_oil
->installed
)
317 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
320 /* FIXME can join_desired actually be changed by pim_rpf_update()
321 * returning PIM_RPF_CHANGED ?
323 pim_upstream_update_join_desired(pim
, up
);
326 static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS
)
329 struct pim_instance
*pim
;
332 pim
= pim_get_pim_instance(vrf_id
);
339 sg
.prefixlen
= stream_getl(s
);
340 stream_get(&sg
.src
.s_addr
, s
, sg
.prefixlen
);
341 stream_get(&sg
.grp
.s_addr
, s
, sg
.prefixlen
);
343 if (PIM_DEBUG_ZEBRA
) {
344 char sg_str
[PIM_SG_LEN
];
346 pim_str_sg_set(&sg
, sg_str
);
347 zlog_debug("%u:recv SG %s %s", vrf_id
,
348 (cmd
== ZEBRA_VXLAN_SG_ADD
)?"add":"del",
352 if (cmd
== ZEBRA_VXLAN_SG_ADD
)
353 pim_vxlan_sg_add(pim
, &sg
);
355 pim_vxlan_sg_del(pim
, &sg
);
360 static void pim_zebra_vxlan_replay(void)
362 struct stream
*s
= NULL
;
365 if (!zclient
|| zclient
->sock
< 0)
371 zclient_create_header(s
, ZEBRA_VXLAN_SG_REPLAY
, VRF_DEFAULT
);
372 stream_putw_at(s
, 0, stream_get_endp(s
));
374 zclient_send_message(zclient
);
377 void pim_scan_oil(struct pim_instance
*pim
)
379 struct channel_oil
*c_oil
;
381 pim
->scan_oil_last
= pim_time_monotonic_sec();
382 ++pim
->scan_oil_events
;
384 frr_each (rb_pim_oil
, &pim
->channel_oil_head
, c_oil
)
385 pim_upstream_mroute_iif_update(c_oil
, __func__
);
388 static int on_rpf_cache_refresh(struct thread
*t
)
390 struct pim_instance
*pim
= THREAD_ARG(t
);
392 /* update kernel multicast forwarding cache (MFC) */
395 pim
->rpf_cache_refresh_last
= pim_time_monotonic_sec();
396 ++pim
->rpf_cache_refresh_events
;
398 // It is called as part of pim_neighbor_add
403 void sched_rpf_cache_refresh(struct pim_instance
*pim
)
405 ++pim
->rpf_cache_refresh_requests
;
407 pim_rpf_set_refresh_time(pim
);
409 if (pim
->rpf_cache_refresher
) {
410 /* Refresh timer is already running */
414 /* Start refresh timer */
416 if (PIM_DEBUG_ZEBRA
) {
417 zlog_debug("%s: triggering %ld msec timer", __func__
,
418 router
->rpf_cache_refresh_delay_msec
);
421 thread_add_timer_msec(router
->master
, on_rpf_cache_refresh
, pim
,
422 router
->rpf_cache_refresh_delay_msec
,
423 &pim
->rpf_cache_refresher
);
426 static void pim_zebra_connected(struct zclient
*zclient
)
428 /* Send the client registration */
429 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
, router
->vrf_id
);
431 zclient_send_reg_requests(zclient
, router
->vrf_id
);
433 /* request for VxLAN BUM group addresses */
434 pim_zebra_vxlan_replay();
437 static void pim_zebra_capabilities(struct zclient_capabilities
*cap
)
439 router
->mlag_role
= cap
->role
;
442 void pim_zebra_init(void)
444 /* Socket for receiving updates from Zebra daemon */
445 zclient
= zclient_new(router
->master
, &zclient_options_default
);
447 zclient
->zebra_capabilities
= pim_zebra_capabilities
;
448 zclient
->zebra_connected
= pim_zebra_connected
;
449 zclient
->router_id_update
= pim_router_id_update_zebra
;
450 zclient
->interface_address_add
= pim_zebra_if_address_add
;
451 zclient
->interface_address_delete
= pim_zebra_if_address_del
;
452 zclient
->interface_vrf_update
= pim_zebra_interface_vrf_update
;
453 zclient
->nexthop_update
= pim_parse_nexthop_update
;
454 zclient
->vxlan_sg_add
= pim_zebra_vxlan_sg_proc
;
455 zclient
->vxlan_sg_del
= pim_zebra_vxlan_sg_proc
;
456 zclient
->mlag_process_up
= pim_zebra_mlag_process_up
;
457 zclient
->mlag_process_down
= pim_zebra_mlag_process_down
;
458 zclient
->mlag_handle_msg
= pim_zebra_mlag_handle_msg
;
460 zclient_init(zclient
, ZEBRA_ROUTE_PIM
, 0, &pimd_privs
);
461 if (PIM_DEBUG_PIM_TRACE
) {
462 zlog_notice("%s: zclient socket initialized", __func__
);
465 zclient_lookup_new();
468 void igmp_anysource_forward_start(struct pim_instance
*pim
,
469 struct igmp_group
*group
)
471 struct igmp_source
*source
;
472 struct in_addr src_addr
= {.s_addr
= 0};
473 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
474 assert(group
->group_filtermode_isexcl
);
475 assert(listcount(group
->group_source_list
) < 1);
477 source
= source_new(group
, src_addr
);
479 zlog_warn("%s: Failure to create * source", __func__
);
483 igmp_source_forward_start(pim
, source
);
486 void igmp_anysource_forward_stop(struct igmp_group
*group
)
488 struct igmp_source
*source
;
489 struct in_addr star
= {.s_addr
= 0};
491 source
= igmp_find_source_by_addr(group
, star
);
493 igmp_source_forward_stop(source
);
496 static void igmp_source_forward_reevaluate_one(struct pim_instance
*pim
,
497 struct igmp_source
*source
)
500 struct igmp_group
*group
= source
->source_group
;
501 struct pim_ifchannel
*ch
;
503 if ((source
->source_addr
.s_addr
!= INADDR_ANY
)
504 || !IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
))
507 memset(&sg
, 0, sizeof(struct prefix_sg
));
508 sg
.src
= source
->source_addr
;
509 sg
.grp
= group
->group_addr
;
511 ch
= pim_ifchannel_find(group
->group_igmp_sock
->interface
, &sg
);
512 if (pim_is_grp_ssm(pim
, group
->group_addr
)) {
513 /* If SSM group withdraw local membership */
515 && (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_INCLUDE
)) {
516 if (PIM_DEBUG_PIM_EVENTS
)
518 "local membership del for %s as G is now SSM",
519 pim_str_sg_dump(&sg
));
520 pim_ifchannel_local_membership_del(
521 group
->group_igmp_sock
->interface
, &sg
);
524 /* If ASM group add local membership */
526 || (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_NOINFO
)) {
527 if (PIM_DEBUG_PIM_EVENTS
)
529 "local membership add for %s as G is now ASM",
530 pim_str_sg_dump(&sg
));
531 pim_ifchannel_local_membership_add(
532 group
->group_igmp_sock
->interface
, &sg
,
538 void igmp_source_forward_reevaluate_all(struct pim_instance
*pim
)
540 struct interface
*ifp
;
542 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
543 struct pim_interface
*pim_ifp
= ifp
->info
;
544 struct listnode
*sock_node
;
545 struct igmp_sock
*igmp
;
550 /* scan igmp sockets */
551 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->igmp_socket_list
, sock_node
,
553 struct listnode
*grpnode
;
554 struct igmp_group
*grp
;
556 /* scan igmp groups */
557 for (ALL_LIST_ELEMENTS_RO(igmp
->igmp_group_list
,
559 struct listnode
*srcnode
;
560 struct igmp_source
*src
;
562 /* scan group sources */
563 for (ALL_LIST_ELEMENTS_RO(
564 grp
->group_source_list
, srcnode
,
566 igmp_source_forward_reevaluate_one(pim
,
568 } /* scan group sources */
569 } /* scan igmp groups */
570 } /* scan igmp sockets */
571 } /* scan interfaces */
574 void igmp_source_forward_start(struct pim_instance
*pim
,
575 struct igmp_source
*source
)
577 struct pim_interface
*pim_oif
;
578 struct igmp_group
*group
;
581 int input_iface_vif_index
= 0;
583 memset(&sg
, 0, sizeof(struct prefix_sg
));
584 sg
.src
= source
->source_addr
;
585 sg
.grp
= source
->source_group
->group_addr
;
587 if (PIM_DEBUG_IGMP_TRACE
) {
589 "%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d", __func__
,
590 pim_str_sg_dump(&sg
),
591 source
->source_group
->group_igmp_sock
->fd
,
592 source
->source_group
->group_igmp_sock
->interface
->name
,
593 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
596 /* Prevent IGMP interface from installing multicast route multiple
598 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
602 group
= source
->source_group
;
603 pim_oif
= group
->group_igmp_sock
->interface
->info
;
605 if (PIM_DEBUG_IGMP_TRACE
) {
606 zlog_debug("%s: multicast not enabled on oif=%s ?",
608 source
->source_group
->group_igmp_sock
614 if (!source
->source_channel_oil
) {
615 struct in_addr vif_source
;
616 struct prefix src
, grp
;
617 struct pim_nexthop nexthop
;
618 struct pim_upstream
*up
= NULL
;
620 if (!pim_rp_set_upstream_addr(pim
, &vif_source
,
621 source
->source_addr
, sg
.grp
)) {
622 /*Create a dummy channel oil */
623 source
->source_channel_oil
=
624 pim_channel_oil_add(pim
, &sg
, __func__
);
628 src
.family
= AF_INET
;
629 src
.prefixlen
= IPV4_MAX_BITLEN
;
630 src
.u
.prefix4
= vif_source
; // RP or Src address
631 grp
.family
= AF_INET
;
632 grp
.prefixlen
= IPV4_MAX_BITLEN
;
633 grp
.u
.prefix4
= sg
.grp
;
635 up
= pim_upstream_find(pim
, &sg
);
637 memcpy(&nexthop
, &up
->rpf
.source_nexthop
,
638 sizeof(struct pim_nexthop
));
639 pim_ecmp_nexthop_lookup(pim
, &nexthop
, &src
,
641 if (nexthop
.interface
)
642 input_iface_vif_index
=
643 pim_if_find_vifindex_by_ifindex(
645 nexthop
.interface
->ifindex
);
647 input_iface_vif_index
=
648 pim_ecmp_fib_lookup_if_vif_index(
651 if (PIM_DEBUG_ZEBRA
) {
652 char buf2
[INET_ADDRSTRLEN
];
654 pim_inet4_dump("<source?>", vif_source
, buf2
,
657 "%s: NHT %s vif_source %s vif_index:%d ",
658 __func__
, pim_str_sg_dump(&sg
), buf2
,
659 input_iface_vif_index
);
662 if (input_iface_vif_index
< 1) {
663 if (PIM_DEBUG_IGMP_TRACE
) {
664 char source_str
[INET_ADDRSTRLEN
];
665 pim_inet4_dump("<source?>",
667 source_str
, sizeof(source_str
));
669 "%s %s: could not find input interface for source %s",
670 __FILE__
, __func__
, source_str
);
672 source
->source_channel_oil
=
673 pim_channel_oil_add(pim
, &sg
, __func__
);
678 * Protect IGMP against adding looped MFC
679 * entries created by both source and receiver
680 * attached to the same interface. See TODO
681 * T22. Block only when the intf is non DR
682 * DR must create upstream.
684 if ((input_iface_vif_index
==
685 pim_oif
->mroute_vif_index
) &&
686 !(PIM_I_am_DR(pim_oif
))) {
687 /* ignore request for looped MFC entry
689 if (PIM_DEBUG_IGMP_TRACE
) {
691 "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
693 pim_str_sg_dump(&sg
),
700 input_iface_vif_index
);
705 source
->source_channel_oil
=
706 pim_channel_oil_add(pim
, &sg
, __func__
);
707 if (!source
->source_channel_oil
) {
708 if (PIM_DEBUG_IGMP_TRACE
) {
710 "%s %s: could not create OIL for channel (S,G)=%s",
712 pim_str_sg_dump(&sg
));
720 if (PIM_I_am_DR(pim_oif
) || PIM_I_am_DualActive(pim_oif
)) {
721 result
= pim_channel_add_oif(source
->source_channel_oil
,
722 group
->group_igmp_sock
->interface
,
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
)
734 "%s: %s was received on %s interface but we are not DR for that interface",
735 __func__
, pim_str_sg_dump(&sg
),
736 group
->group_igmp_sock
->interface
->name
);
741 Feed IGMPv3-gathered local membership information into PIM
742 per-interface (S,G) state.
744 if (!pim_ifchannel_local_membership_add(
745 group
->group_igmp_sock
->interface
, &sg
,
746 false /*is_vxlan*/)) {
747 if (PIM_DEBUG_MROUTE
)
748 zlog_warn("%s: Failure to add local membership for %s",
749 __func__
, pim_str_sg_dump(&sg
));
751 pim_channel_del_oif(source
->source_channel_oil
,
752 group
->group_igmp_sock
->interface
,
753 PIM_OIF_FLAG_PROTO_IGMP
, __func__
);
757 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
761 igmp_source_forward_stop: stop fowarding, but keep the source
762 igmp_source_delete: stop fowarding, and delete the source
764 void igmp_source_forward_stop(struct igmp_source
*source
)
766 struct igmp_group
*group
;
770 memset(&sg
, 0, sizeof(struct prefix_sg
));
771 sg
.src
= source
->source_addr
;
772 sg
.grp
= source
->source_group
->group_addr
;
774 if (PIM_DEBUG_IGMP_TRACE
) {
776 "%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d", __func__
,
777 pim_str_sg_dump(&sg
),
778 source
->source_group
->group_igmp_sock
->fd
,
779 source
->source_group
->group_igmp_sock
->interface
->name
,
780 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
783 /* Prevent IGMP interface from removing multicast route multiple
785 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
789 group
= source
->source_group
;
792 It appears that in certain circumstances that
793 igmp_source_forward_stop is called when IGMP forwarding
794 was not enabled in oif_flags for this outgoing interface.
795 Possibly because of multiple calls. When that happens, we
796 enter the below if statement and this function returns early
797 which in turn triggers the calling function to assert.
798 Making the call to pim_channel_del_oif and ignoring the return code
799 fixes the issue without ill effect, similar to
800 pim_forward_stop below.
802 result
= pim_channel_del_oif(source
->source_channel_oil
,
803 group
->group_igmp_sock
->interface
,
804 PIM_OIF_FLAG_PROTO_IGMP
,
807 if (PIM_DEBUG_IGMP_TRACE
)
809 "%s: pim_channel_del_oif() failed with return=%d",
815 Feed IGMPv3-gathered local membership information into PIM
816 per-interface (S,G) state.
818 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
821 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
824 void pim_forward_start(struct pim_ifchannel
*ch
)
826 struct pim_upstream
*up
= ch
->upstream
;
829 if (PIM_DEBUG_PIM_TRACE
) {
830 char source_str
[INET_ADDRSTRLEN
];
831 char group_str
[INET_ADDRSTRLEN
];
832 char upstream_str
[INET_ADDRSTRLEN
];
834 pim_inet4_dump("<source?>", ch
->sg
.src
, source_str
,
836 pim_inet4_dump("<group?>", ch
->sg
.grp
, group_str
,
838 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
,
839 sizeof(upstream_str
));
840 zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%pI4)", __func__
,
841 source_str
, group_str
, ch
->interface
->name
,
845 if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch
->flags
))
846 mask
= PIM_OIF_FLAG_PROTO_IGMP
;
848 if (PIM_IF_FLAG_TEST_PROTO_PIM(ch
->flags
))
849 mask
|= PIM_OIF_FLAG_PROTO_PIM
;
851 pim_channel_add_oif(up
->channel_oil
, ch
->interface
,
855 void pim_forward_stop(struct pim_ifchannel
*ch
, bool install_it
)
857 struct pim_upstream
*up
= ch
->upstream
;
859 if (PIM_DEBUG_PIM_TRACE
) {
860 zlog_debug("%s: (S,G)=%s oif=%s install_it: %d installed: %d",
861 __func__
, ch
->sg_str
, ch
->interface
->name
,
862 install_it
, up
->channel_oil
->installed
);
866 * If a channel is being removed, check to see if we still need
867 * to inherit the interface. If so make sure it is added in
869 if (pim_upstream_evaluate_join_desired_interface(up
, ch
, ch
->parent
))
870 pim_channel_add_oif(up
->channel_oil
, ch
->interface
,
871 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
873 pim_channel_del_oif(up
->channel_oil
, ch
->interface
,
874 PIM_OIF_FLAG_PROTO_PIM
, __func__
);
876 if (install_it
&& !up
->channel_oil
->installed
)
877 pim_upstream_mroute_add(up
->channel_oil
, __func__
);
880 void pim_zebra_zclient_update(struct vty
*vty
)
882 vty_out(vty
, "Zclient update socket: ");
885 vty_out(vty
, "%d failures=%d\n", zclient
->sock
, zclient
->fail
);
887 vty_out(vty
, "<null zclient>\n");
891 struct zclient
*pim_zebra_zclient_get(void)
899 void pim_zebra_interface_set_master(struct interface
*vrf
,
900 struct interface
*ifp
)
902 zclient_interface_set_master(zclient
, vrf
, ifp
);