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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
23 #include "zebra/rib.h"
36 #include "pim_zebra.h"
37 #include "pim_iface.h"
43 #include "pim_zlookup.h"
44 #include "pim_ifchannel.h"
46 #include "pim_igmpv3.h"
47 #include "pim_jp_agg.h"
51 #undef PIM_DEBUG_IFADDR_DUMP
52 #define PIM_DEBUG_IFADDR_DUMP
54 static struct zclient
*zclient
= NULL
;
57 /* Router-id update message from zebra. */
58 static int pim_router_id_update_zebra(int command
, struct zclient
*zclient
,
59 zebra_size_t length
, vrf_id_t vrf_id
)
61 struct prefix router_id
;
63 zebra_router_id_update_read(zclient
->ibuf
, &router_id
);
68 static int pim_zebra_if_add(int command
, struct zclient
*zclient
,
69 zebra_size_t length
, vrf_id_t vrf_id
)
71 struct interface
*ifp
;
74 zebra api adds/dels interfaces using the same call
75 interface_add_read below, see comments in lib/zclient.c
77 ifp
= zebra_interface_add_read(zclient
->ibuf
, vrf_id
);
81 if (PIM_DEBUG_ZEBRA
) {
82 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
84 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
85 ifp
->mtu
, if_is_operative(ifp
));
88 if (if_is_operative(ifp
))
89 pim_if_addr_add_all(ifp
);
94 static int pim_zebra_if_del(int command
, struct zclient
*zclient
,
95 zebra_size_t length
, vrf_id_t vrf_id
)
97 struct interface
*ifp
;
100 zebra api adds/dels interfaces using the same call
101 interface_add_read below, see comments in lib/zclient.c
103 comments in lib/zclient.c seem to indicate that calling
104 zebra_interface_add_read is the correct call, but that
105 results in an attemted out of bounds read which causes
106 pimd to assert. Other clients use zebra_interface_state_read
107 and it appears to work just fine.
109 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
113 if (PIM_DEBUG_ZEBRA
) {
114 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
116 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
117 ifp
->mtu
, if_is_operative(ifp
));
120 if (!if_is_operative(ifp
))
121 pim_if_addr_del_all(ifp
);
126 static int pim_zebra_if_state_up(int command
, struct zclient
*zclient
,
127 zebra_size_t length
, vrf_id_t vrf_id
)
129 struct interface
*ifp
;
132 zebra api notifies interface up/down events by using the same call
133 zebra_interface_state_read below, see comments in lib/zclient.c
135 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
139 if (PIM_DEBUG_ZEBRA
) {
140 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
142 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
143 ifp
->mtu
, if_is_operative(ifp
));
146 if (if_is_operative(ifp
)) {
148 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
150 pim_if_addr_add_all(ifp
);
156 static int pim_zebra_if_state_down(int command
, struct zclient
*zclient
,
157 zebra_size_t length
, vrf_id_t vrf_id
)
159 struct interface
*ifp
;
162 zebra api notifies interface up/down events by using the same call
163 zebra_interface_state_read below, see comments in lib/zclient.c
165 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
169 if (PIM_DEBUG_ZEBRA
) {
170 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
172 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
173 ifp
->mtu
, if_is_operative(ifp
));
176 if (!if_is_operative(ifp
)) {
177 pim_ifchannel_delete_all(ifp
);
179 pim_if_addr_del_all() suffices for shutting down IGMP,
180 but not for shutting down PIM
182 pim_if_addr_del_all(ifp
);
185 pim_sock_delete() closes the socket, stops read and timer threads,
186 and kills all neighbors.
189 pim_sock_delete(ifp
, "link down");
199 #ifdef PIM_DEBUG_IFADDR_DUMP
200 static void dump_if_address(struct interface
*ifp
)
202 struct connected
*ifc
;
203 struct listnode
*node
;
205 zlog_debug("%s %s: interface %s addresses:",
206 __FILE__
, __PRETTY_FUNCTION__
,
209 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
210 struct prefix
*p
= ifc
->address
;
212 if (p
->family
!= AF_INET
)
215 zlog_debug("%s %s: interface %s address %s %s",
216 __FILE__
, __PRETTY_FUNCTION__
,
218 inet_ntoa(p
->u
.prefix4
),
219 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
220 "secondary" : "primary");
225 static int pim_zebra_if_address_add(int command
, struct zclient
*zclient
,
226 zebra_size_t length
, vrf_id_t vrf_id
)
230 struct pim_interface
*pim_ifp
;
233 zebra api notifies address adds/dels events by using the same call
234 interface_add_read below, see comments in lib/zclient.c
236 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
237 will add address to interface list by calling
238 connected_add_by_prefix()
240 c
= zebra_interface_address_read(command
, zclient
->ibuf
, vrf_id
);
244 pim_ifp
= c
->ifp
->info
;
247 if (PIM_DEBUG_ZEBRA
) {
249 prefix2str(p
, buf
, BUFSIZ
);
250 zlog_debug("%s: %s connected IP address %s flags %u %s",
252 c
->ifp
->name
, buf
, c
->flags
,
253 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
255 #ifdef PIM_DEBUG_IFADDR_DUMP
256 dump_if_address(c
->ifp
);
260 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
261 /* trying to add primary address */
263 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
264 if (p
->family
!= AF_INET
|| primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
265 if (PIM_DEBUG_ZEBRA
) {
266 /* but we had a primary address already */
270 prefix2str(p
, buf
, BUFSIZ
);
272 zlog_warn("%s: %s : forcing secondary flag on %s",
276 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
282 pim_rp_check_on_if_add(pim_ifp
);
284 if (if_is_loopback (c
->ifp
))
286 struct listnode
*ifnode
;
287 struct interface
*ifp
;
289 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
))
291 if (!if_is_loopback (ifp
) && if_is_operative (ifp
))
292 pim_if_addr_add_all (ifp
);
299 static int pim_zebra_if_address_del(int command
, struct zclient
*client
,
300 zebra_size_t length
, vrf_id_t vrf_id
)
306 zebra api notifies address adds/dels events by using the same call
307 interface_add_read below, see comments in lib/zclient.c
309 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
310 will remove address from interface list by calling
311 connected_delete_by_prefix()
313 c
= zebra_interface_address_read(command
, client
->ibuf
, vrf_id
);
318 if (p
->family
== AF_INET
)
320 if (PIM_DEBUG_ZEBRA
) {
322 prefix2str(p
, buf
, BUFSIZ
);
323 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
325 c
->ifp
->name
, buf
, c
->flags
,
326 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
328 #ifdef PIM_DEBUG_IFADDR_DUMP
329 dump_if_address(c
->ifp
);
333 pim_if_addr_del(c
, 0);
335 pim_i_am_rp_re_evaluate();
342 static void scan_upstream_rpf_cache()
344 struct listnode
*up_node
;
345 struct listnode
*ifnode
;
346 struct listnode
*up_nextnode
;
347 struct listnode
*node
;
348 struct pim_upstream
*up
;
349 struct interface
*ifp
;
351 for (ALL_LIST_ELEMENTS(pim_upstream_list
, up_node
, up_nextnode
, up
)) {
352 enum pim_rpf_result rpf_result
;
356 nht_p
.family
= AF_INET
;
357 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
358 nht_p
.u
.prefix4
.s_addr
= up
->upstream_addr
.s_addr
;
359 pim_resolve_upstream_nh (&nht_p
);
361 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
362 old
.source_nexthop
.nbr
= up
->rpf
.source_nexthop
.nbr
;
363 rpf_result
= pim_rpf_update(up
, &old
, 0);
365 if (rpf_result
== PIM_RPF_FAILURE
)
368 if (rpf_result
== PIM_RPF_CHANGED
) {
369 struct pim_neighbor
*nbr
;
371 nbr
= pim_neighbor_find (old
.source_nexthop
.interface
,
372 old
.rpf_addr
.u
.prefix4
);
374 pim_jp_agg_remove_group (nbr
->upstream_jp_agg
, up
);
377 * We have detected a case where we might need to rescan
378 * the inherited o_list so do it.
380 if (up
->channel_oil
->oil_inherited_rescan
)
382 pim_upstream_inherited_olist_decide (up
);
383 up
->channel_oil
->oil_inherited_rescan
= 0;
386 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
388 * If we come up real fast we can be here
389 * where the mroute has not been installed
392 if (!up
->channel_oil
->installed
)
393 pim_mroute_add (up
->channel_oil
, __PRETTY_FUNCTION__
);
396 * RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
398 * Transitions from Joined State
400 * RPF'(S,G) changes not due to an Assert
402 * The upstream (S,G) state machine remains in Joined
403 * state. Send Join(S,G) to the new upstream neighbor, which is
404 * the new value of RPF'(S,G). Send Prune(S,G) to the old
405 * upstream neighbor, which is the old value of RPF'(S,G). Set
406 * the Join Timer (JT) to expire after t_periodic seconds.
408 pim_jp_agg_switch_interface (&old
, &up
->rpf
, up
);
410 pim_upstream_join_timer_restart(up
, &old
);
411 } /* up->join_state == PIM_UPSTREAM_JOINED */
413 /* FIXME can join_desired actually be changed by pim_rpf_update()
414 returning PIM_RPF_CHANGED ? */
415 pim_upstream_update_join_desired(up
);
417 } /* PIM_RPF_CHANGED */
419 } /* for (qpim_upstream_list) */
421 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
))
424 struct pim_interface
*pim_ifp
= ifp
->info
;
425 struct pim_iface_upstream_switch
*us
;
427 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->upstream_switch_list
, node
, us
))
430 rpf
.source_nexthop
.interface
= ifp
;
431 rpf
.rpf_addr
.u
.prefix4
= us
->address
;
432 pim_joinprune_send(&rpf
, us
->us
);
433 pim_jp_agg_clear_group(us
->us
);
439 pim_scan_individual_oil (struct channel_oil
*c_oil
, int in_vif_index
)
441 struct in_addr vif_source
;
442 int input_iface_vif_index
;
445 if (!pim_rp_set_upstream_addr (&vif_source
, c_oil
->oil
.mfcc_origin
, c_oil
->oil
.mfcc_mcastgrp
))
449 input_iface_vif_index
= in_vif_index
;
452 struct prefix src
, grp
;
454 src
.family
= AF_INET
;
455 src
.prefixlen
= IPV4_MAX_BITLEN
;
456 src
.u
.prefix4
= vif_source
;
457 grp
.family
= AF_INET
;
458 grp
.prefixlen
= IPV4_MAX_BITLEN
;
459 grp
.u
.prefix4
= c_oil
->oil
.mfcc_mcastgrp
;
463 char source_str
[INET_ADDRSTRLEN
];
464 char group_str
[INET_ADDRSTRLEN
];
465 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
466 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
467 zlog_debug ("%s: channel_oil (%s, %s) upstream info is not present.",
468 __PRETTY_FUNCTION__
, source_str
, group_str
);
470 input_iface_vif_index
= pim_ecmp_fib_lookup_if_vif_index(vif_source
, &src
, &grp
);
473 if (input_iface_vif_index
< 1)
477 char source_str
[INET_ADDRSTRLEN
];
478 char group_str
[INET_ADDRSTRLEN
];
479 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
480 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
481 zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
482 __FILE__
, __PRETTY_FUNCTION__
, c_oil
->oil
.mfcc_parent
,
483 source_str
, group_str
);
485 pim_mroute_del (c_oil
, __PRETTY_FUNCTION__
);
489 if (input_iface_vif_index
== c_oil
->oil
.mfcc_parent
)
491 if (!c_oil
->installed
)
492 pim_mroute_add (c_oil
, __PRETTY_FUNCTION__
);
500 struct interface
*old_iif
= pim_if_find_by_vif_index(c_oil
->oil
.mfcc_parent
);
501 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
502 char source_str
[INET_ADDRSTRLEN
];
503 char group_str
[INET_ADDRSTRLEN
];
504 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
505 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
506 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
507 __FILE__
, __PRETTY_FUNCTION__
,
508 source_str
, group_str
,
509 old_iif
->name
, c_oil
->oil
.mfcc_parent
,
510 new_iif
->name
, input_iface_vif_index
);
513 /* new iif loops to existing oif ? */
514 if (c_oil
->oil
.mfcc_ttls
[input_iface_vif_index
])
516 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
518 if (PIM_DEBUG_ZEBRA
) {
519 char source_str
[INET_ADDRSTRLEN
];
520 char group_str
[INET_ADDRSTRLEN
];
521 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
522 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
523 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
524 __FILE__
, __PRETTY_FUNCTION__
,
525 source_str
, group_str
,
526 new_iif
->name
, input_iface_vif_index
);
530 /* update iif vif_index */
531 old_vif_index
= c_oil
->oil
.mfcc_parent
;
532 c_oil
->oil
.mfcc_parent
= input_iface_vif_index
;
534 /* update kernel multicast forwarding cache (MFC) */
535 if (pim_mroute_add(c_oil
, __PRETTY_FUNCTION__
))
537 if (PIM_DEBUG_MROUTE
)
539 /* just log warning */
540 struct interface
*old_iif
= pim_if_find_by_vif_index(old_vif_index
);
541 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
542 char source_str
[INET_ADDRSTRLEN
];
543 char group_str
[INET_ADDRSTRLEN
];
544 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
545 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
546 zlog_debug("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
547 __FILE__
, __PRETTY_FUNCTION__
,
548 source_str
, group_str
,
549 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
550 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
557 struct listnode
*node
;
558 struct listnode
*nextnode
;
559 struct channel_oil
*c_oil
;
563 qpim_scan_oil_last
= pim_time_monotonic_sec();
564 ++qpim_scan_oil_events
;
566 for (ALL_LIST_ELEMENTS(pim_channel_oil_list
, node
, nextnode
, c_oil
))
568 if (c_oil
->up
&& c_oil
->up
->rpf
.source_nexthop
.interface
)
570 ifindex
= c_oil
->up
->rpf
.source_nexthop
.interface
->ifindex
;
571 vif_index
= pim_if_find_vifindex_by_ifindex (ifindex
);
572 /* Pass Current selected NH vif index to mroute download */
574 pim_scan_individual_oil (c_oil
, vif_index
);
577 pim_scan_individual_oil (c_oil
, 0);
581 static int on_rpf_cache_refresh(struct thread
*t
)
583 zassert(qpim_rpf_cache_refresher
);
585 qpim_rpf_cache_refresher
= 0;
587 /* update PIM protocol state */
588 scan_upstream_rpf_cache();
590 /* update kernel multicast forwarding cache (MFC) */
593 qpim_rpf_cache_refresh_last
= pim_time_monotonic_sec();
594 ++qpim_rpf_cache_refresh_events
;
596 //It is called as part of pim_neighbor_add
601 void sched_rpf_cache_refresh(void)
603 ++qpim_rpf_cache_refresh_requests
;
605 pim_rpf_set_refresh_time ();
607 if (qpim_rpf_cache_refresher
) {
608 /* Refresh timer is already running */
612 /* Start refresh timer */
614 if (PIM_DEBUG_ZEBRA
) {
615 zlog_debug("%s: triggering %ld msec timer",
617 qpim_rpf_cache_refresh_delay_msec
);
620 THREAD_TIMER_MSEC_ON(master
, qpim_rpf_cache_refresher
,
621 on_rpf_cache_refresh
,
622 0, qpim_rpf_cache_refresh_delay_msec
);
626 pim_zebra_connected (struct zclient
*zclient
)
628 zclient_send_reg_requests (zclient
, VRF_DEFAULT
);
631 void pim_zebra_init(void)
635 #ifdef HAVE_TCP_ZEBRA
636 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT
);
638 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
641 /* Socket for receiving updates from Zebra daemon */
642 zclient
= zclient_new (master
);
644 zclient
->zebra_connected
= pim_zebra_connected
;
645 zclient
->router_id_update
= pim_router_id_update_zebra
;
646 zclient
->interface_add
= pim_zebra_if_add
;
647 zclient
->interface_delete
= pim_zebra_if_del
;
648 zclient
->interface_up
= pim_zebra_if_state_up
;
649 zclient
->interface_down
= pim_zebra_if_state_down
;
650 zclient
->interface_address_add
= pim_zebra_if_address_add
;
651 zclient
->interface_address_delete
= pim_zebra_if_address_del
;
652 zclient
->nexthop_update
= pim_parse_nexthop_update
;
654 zclient_init(zclient
, ZEBRA_ROUTE_PIM
, 0);
655 if (PIM_DEBUG_PIM_TRACE
) {
656 zlog_info("zclient_init cleared redistribution request");
659 zassert(zclient
->redist_default
== ZEBRA_ROUTE_PIM
);
661 /* Request all redistribution */
662 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
663 if (i
== zclient
->redist_default
)
665 vrf_bitmap_set (zclient
->redist
[AFI_IP
][i
], VRF_DEFAULT
);;
666 if (PIM_DEBUG_PIM_TRACE
) {
667 zlog_debug("%s: requesting redistribution for %s (%i)",
668 __PRETTY_FUNCTION__
, zebra_route_string(i
), i
);
672 /* Request default information */
673 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
674 zclient
, VRF_DEFAULT
);
676 if (PIM_DEBUG_PIM_TRACE
) {
677 zlog_info("%s: requesting default information redistribution",
678 __PRETTY_FUNCTION__
);
680 zlog_notice("%s: zclient update socket initialized",
681 __PRETTY_FUNCTION__
);
684 zclient_lookup_new();
687 void igmp_anysource_forward_start(struct igmp_group
*group
)
689 struct igmp_source
*source
;
690 struct in_addr src_addr
= { .s_addr
= 0 };
691 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
692 zassert(group
->group_filtermode_isexcl
);
693 zassert(listcount(group
->group_source_list
) < 1);
695 source
= source_new (group
, src_addr
);
698 zlog_warn ("%s: Failure to create * source", __PRETTY_FUNCTION__
);
702 igmp_source_forward_start (source
);
705 void igmp_anysource_forward_stop(struct igmp_group
*group
)
707 struct igmp_source
*source
;
708 struct in_addr star
= { .s_addr
= 0 };
710 source
= igmp_find_source_by_addr (group
, star
);
712 igmp_source_forward_stop (source
);
716 igmp_source_forward_reevaluate_one(struct igmp_source
*source
)
719 struct igmp_group
*group
= source
->source_group
;
720 struct pim_ifchannel
*ch
;
722 if ((source
->source_addr
.s_addr
!= INADDR_ANY
) ||
723 !IGMP_SOURCE_TEST_FORWARDING (source
->source_flags
))
726 memset (&sg
, 0, sizeof (struct prefix_sg
));
727 sg
.src
= source
->source_addr
;
728 sg
.grp
= group
->group_addr
;
730 ch
= pim_ifchannel_find (group
->group_igmp_sock
->interface
, &sg
);
731 if (pim_is_grp_ssm (group
->group_addr
))
733 /* If SSM group withdraw local membership */
734 if (ch
&& (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_INCLUDE
))
736 if (PIM_DEBUG_PIM_EVENTS
)
737 zlog_debug ("local membership del for %s as G is now SSM",
738 pim_str_sg_dump (&sg
));
739 pim_ifchannel_local_membership_del (group
->group_igmp_sock
->interface
, &sg
);
744 /* If ASM group add local membership */
745 if (!ch
|| (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_NOINFO
))
747 if (PIM_DEBUG_PIM_EVENTS
)
748 zlog_debug ("local membership add for %s as G is now ASM",
749 pim_str_sg_dump (&sg
));
750 pim_ifchannel_local_membership_add (group
->group_igmp_sock
->interface
, &sg
);
756 igmp_source_forward_reevaluate_all(void)
758 struct listnode
*ifnode
;
759 struct interface
*ifp
;
761 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
))
763 struct pim_interface
*pim_ifp
= ifp
->info
;
764 struct listnode
*sock_node
;
765 struct igmp_sock
*igmp
;
770 /* scan igmp sockets */
771 for (ALL_LIST_ELEMENTS_RO (pim_ifp
->igmp_socket_list
, sock_node
, igmp
))
773 struct listnode
*grpnode
;
774 struct igmp_group
*grp
;
776 /* scan igmp groups */
777 for (ALL_LIST_ELEMENTS_RO (igmp
->igmp_group_list
, grpnode
, grp
))
779 struct listnode
*srcnode
;
780 struct igmp_source
*src
;
782 /* scan group sources */
783 for (ALL_LIST_ELEMENTS_RO (grp
->group_source_list
,
786 igmp_source_forward_reevaluate_one (src
);
787 } /* scan group sources */
788 } /* scan igmp groups */
789 } /* scan igmp sockets */
790 } /* scan interfaces */
793 void igmp_source_forward_start(struct igmp_source
*source
)
795 struct igmp_group
*group
;
798 int input_iface_vif_index
= 0;
800 memset (&sg
, 0, sizeof (struct prefix_sg
));
801 sg
.src
= source
->source_addr
;
802 sg
.grp
= source
->source_group
->group_addr
;
804 if (PIM_DEBUG_IGMP_TRACE
) {
805 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
807 pim_str_sg_dump (&sg
),
808 source
->source_group
->group_igmp_sock
->fd
,
809 source
->source_group
->group_igmp_sock
->interface
->name
,
810 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
813 /* Prevent IGMP interface from installing multicast route multiple
815 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
819 group
= source
->source_group
;
821 if (!source
->source_channel_oil
) {
822 struct in_addr vif_source
;
823 struct pim_interface
*pim_oif
;
824 struct prefix nht_p
, src
, grp
;
826 struct pim_nexthop_cache out_pnc
;
827 struct pim_nexthop nexthop
;
828 struct pim_upstream
*up
= NULL
;
830 if (!pim_rp_set_upstream_addr (&vif_source
, source
->source_addr
, sg
.grp
))
833 /* Register addr with Zebra NHT */
834 nht_p
.family
= AF_INET
;
835 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
836 nht_p
.u
.prefix4
= vif_source
;
837 memset (&out_pnc
, 0, sizeof (struct pim_nexthop_cache
));
839 src
.family
= AF_INET
;
840 src
.prefixlen
= IPV4_MAX_BITLEN
;
841 src
.u
.prefix4
= vif_source
; //RP or Src address
842 grp
.family
= AF_INET
;
843 grp
.prefixlen
= IPV4_MAX_BITLEN
;
844 grp
.u
.prefix4
= sg
.grp
;
846 if ((ret
= pim_find_or_track_nexthop (&nht_p
, NULL
, NULL
, &out_pnc
)) == 1)
848 if (out_pnc
.nexthop_num
)
850 up
= pim_upstream_find (&sg
);
851 memset (&nexthop
, 0, sizeof (struct pim_nexthop
));
853 memcpy (&nexthop
, &up
->rpf
.source_nexthop
, sizeof (struct pim_nexthop
));
854 //Compute PIM RPF using Cached nexthop
855 pim_ecmp_nexthop_search (&out_pnc
, &nexthop
, &src
, &grp
, 0);
856 if (nexthop
.interface
)
857 input_iface_vif_index
= pim_if_find_vifindex_by_ifindex (nexthop
.interface
->ifindex
);
863 char buf1
[INET_ADDRSTRLEN
];
864 char buf2
[INET_ADDRSTRLEN
];
865 pim_inet4_dump("<source?>", nht_p
.u
.prefix4
, buf1
, sizeof(buf1
));
866 pim_inet4_dump("<source?>", grp
.u
.prefix4
, buf2
, sizeof(buf2
));
867 zlog_debug ("%s: NHT Nexthop not found for addr %s grp %s" ,
868 __PRETTY_FUNCTION__
, buf1
, buf2
);
873 input_iface_vif_index
= pim_ecmp_fib_lookup_if_vif_index(vif_source
, &src
, &grp
);
877 char buf2
[INET_ADDRSTRLEN
];
878 pim_inet4_dump("<source?>", vif_source
, buf2
, sizeof(buf2
));
879 zlog_debug ("%s: NHT %s vif_source %s vif_index:%d ", __PRETTY_FUNCTION__
,
880 pim_str_sg_dump (&sg
), buf2
, input_iface_vif_index
);
883 if (input_iface_vif_index
< 1) {
884 if (PIM_DEBUG_IGMP_TRACE
)
886 char source_str
[INET_ADDRSTRLEN
];
887 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
888 zlog_debug("%s %s: could not find input interface for source %s",
889 __FILE__
, __PRETTY_FUNCTION__
,
896 Protect IGMP against adding looped MFC entries created by both
897 source and receiver attached to the same interface. See TODO
900 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
902 if (PIM_DEBUG_IGMP_TRACE
)
904 zlog_debug("%s: multicast not enabled on oif=%s ?",
906 source
->source_group
->group_igmp_sock
->interface
->name
);
911 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
912 /* ignore request for looped MFC entry */
913 if (PIM_DEBUG_IGMP_TRACE
) {
914 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
916 pim_str_sg_dump (&sg
),
917 source
->source_group
->group_igmp_sock
->fd
,
918 source
->source_group
->group_igmp_sock
->interface
->name
,
919 input_iface_vif_index
);
924 source
->source_channel_oil
= pim_channel_oil_add(&sg
,
925 input_iface_vif_index
);
926 if (!source
->source_channel_oil
) {
927 if (PIM_DEBUG_IGMP_TRACE
)
929 zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
930 __FILE__
, __PRETTY_FUNCTION__
,
931 pim_str_sg_dump (&sg
));
937 result
= pim_channel_add_oif(source
->source_channel_oil
,
938 group
->group_igmp_sock
->interface
,
939 PIM_OIF_FLAG_PROTO_IGMP
);
941 if (PIM_DEBUG_MROUTE
)
943 zlog_warn("%s: add_oif() failed with return=%d",
950 Feed IGMPv3-gathered local membership information into PIM
951 per-interface (S,G) state.
953 if (!pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
, &sg
))
955 if (PIM_DEBUG_MROUTE
)
956 zlog_warn ("%s: Failure to add local membership for %s",
957 __PRETTY_FUNCTION__
, pim_str_sg_dump (&sg
));
961 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
965 igmp_source_forward_stop: stop fowarding, but keep the source
966 igmp_source_delete: stop fowarding, and delete the source
968 void igmp_source_forward_stop(struct igmp_source
*source
)
970 struct igmp_group
*group
;
974 memset (&sg
, 0, sizeof (struct prefix_sg
));
975 sg
.src
= source
->source_addr
;
976 sg
.grp
= source
->source_group
->group_addr
;
978 if (PIM_DEBUG_IGMP_TRACE
) {
979 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
981 pim_str_sg_dump (&sg
),
982 source
->source_group
->group_igmp_sock
->fd
,
983 source
->source_group
->group_igmp_sock
->interface
->name
,
984 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
987 /* Prevent IGMP interface from removing multicast route multiple
989 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
993 group
= source
->source_group
;
996 It appears that in certain circumstances that
997 igmp_source_forward_stop is called when IGMP forwarding
998 was not enabled in oif_flags for this outgoing interface.
999 Possibly because of multiple calls. When that happens, we
1000 enter the below if statement and this function returns early
1001 which in turn triggers the calling function to assert.
1002 Making the call to pim_channel_del_oif and ignoring the return code
1003 fixes the issue without ill effect, similar to
1004 pim_forward_stop below.
1006 result
= pim_channel_del_oif(source
->source_channel_oil
,
1007 group
->group_igmp_sock
->interface
,
1008 PIM_OIF_FLAG_PROTO_IGMP
);
1010 if (PIM_DEBUG_IGMP_TRACE
)
1011 zlog_debug("%s: pim_channel_del_oif() failed with return=%d",
1017 Feed IGMPv3-gathered local membership information into PIM
1018 per-interface (S,G) state.
1020 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1023 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1026 void pim_forward_start(struct pim_ifchannel
*ch
)
1028 struct pim_upstream
*up
= ch
->upstream
;
1029 uint32_t mask
= PIM_OIF_FLAG_PROTO_PIM
;
1030 int input_iface_vif_index
= 0;
1032 if (PIM_DEBUG_PIM_TRACE
) {
1033 char source_str
[INET_ADDRSTRLEN
];
1034 char group_str
[INET_ADDRSTRLEN
];
1035 char upstream_str
[INET_ADDRSTRLEN
];
1037 pim_inet4_dump("<source?>", ch
->sg
.src
, source_str
, sizeof(source_str
));
1038 pim_inet4_dump("<group?>", ch
->sg
.grp
, group_str
, sizeof(group_str
));
1039 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
, sizeof(upstream_str
));
1040 zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)",
1041 __PRETTY_FUNCTION__
,
1042 source_str
, group_str
, ch
->interface
->name
, upstream_str
);
1045 /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
1046 as part of mroute_del called by pim_forward_stop.
1048 if (!up
->channel_oil
||
1049 (up
->channel_oil
&& up
->channel_oil
->oil
.mfcc_parent
>= MAXVIFS
))
1051 struct prefix nht_p
, src
, grp
;
1053 struct pim_nexthop_cache out_pnc
;
1055 /* Register addr with Zebra NHT */
1056 nht_p
.family
= AF_INET
;
1057 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1058 nht_p
.u
.prefix4
.s_addr
= up
->upstream_addr
.s_addr
;
1059 grp
.family
= AF_INET
;
1060 grp
.prefixlen
= IPV4_MAX_BITLEN
;
1061 grp
.u
.prefix4
= up
->sg
.grp
;
1062 memset (&out_pnc
, 0, sizeof (struct pim_nexthop_cache
));
1064 if ((ret
= pim_find_or_track_nexthop (&nht_p
, NULL
, NULL
, &out_pnc
)) == 1)
1066 if (out_pnc
.nexthop_num
)
1068 src
.family
= AF_INET
;
1069 src
.prefixlen
= IPV4_MAX_BITLEN
;
1070 src
.u
.prefix4
= up
->upstream_addr
; //RP or Src address
1071 grp
.family
= AF_INET
;
1072 grp
.prefixlen
= IPV4_MAX_BITLEN
;
1073 grp
.u
.prefix4
= up
->sg
.grp
;
1074 //Compute PIM RPF using Cached nexthop
1075 if (pim_ecmp_nexthop_search (&out_pnc
, &up
->rpf
.source_nexthop
, &src
, &grp
, 0) == 0)
1076 input_iface_vif_index
= pim_if_find_vifindex_by_ifindex (up
->rpf
.source_nexthop
.interface
->ifindex
);
1079 if (PIM_DEBUG_TRACE
)
1080 zlog_debug ("%s: Nexthop selection failed for %s ", __PRETTY_FUNCTION__
, up
->sg_str
);
1085 if (PIM_DEBUG_ZEBRA
)
1087 char buf1
[INET_ADDRSTRLEN
];
1088 char buf2
[INET_ADDRSTRLEN
];
1089 pim_inet4_dump("<source?>", nht_p
.u
.prefix4
, buf1
, sizeof(buf1
));
1090 pim_inet4_dump("<source?>", grp
.u
.prefix4
, buf2
, sizeof(buf2
));
1091 zlog_debug ("%s: NHT pnc is NULL for addr %s grp %s" ,
1092 __PRETTY_FUNCTION__
, buf1
, buf2
);
1097 input_iface_vif_index
= pim_ecmp_fib_lookup_if_vif_index(up
->upstream_addr
, &src
, &grp
);
1099 if (input_iface_vif_index
< 1)
1101 if (PIM_DEBUG_PIM_TRACE
)
1103 char source_str
[INET_ADDRSTRLEN
];
1104 pim_inet4_dump("<source?>", up
->sg
.src
, source_str
, sizeof(source_str
));
1105 zlog_debug("%s %s: could not find input interface for source %s",
1106 __FILE__
, __PRETTY_FUNCTION__
,
1111 if (PIM_DEBUG_TRACE
)
1113 struct interface
*in_intf
= pim_if_find_by_vif_index (input_iface_vif_index
);
1114 zlog_debug ("%s: Update channel_oil IIF %s VIFI %d entry %s ",
1115 __PRETTY_FUNCTION__
, in_intf
? in_intf
->name
: "NIL",
1116 input_iface_vif_index
, up
->sg_str
);
1118 up
->channel_oil
= pim_channel_oil_add (&up
->sg
, input_iface_vif_index
);
1119 if (!up
->channel_oil
)
1121 if (PIM_DEBUG_PIM_TRACE
)
1122 zlog_debug ("%s %s: could not create OIL for channel (S,G)=%s",
1123 __FILE__
, __PRETTY_FUNCTION__
, up
->sg_str
);
1128 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_IGMP
)
1129 mask
= PIM_OIF_FLAG_PROTO_IGMP
;
1131 pim_channel_add_oif (up
->channel_oil
, ch
->interface
, mask
);
1134 void pim_forward_stop(struct pim_ifchannel
*ch
)
1136 struct pim_upstream
*up
= ch
->upstream
;
1138 if (PIM_DEBUG_PIM_TRACE
) {
1139 zlog_debug("%s: (S,G)=%s oif=%s",
1140 __PRETTY_FUNCTION__
,
1141 ch
->sg_str
, ch
->interface
->name
);
1144 pim_channel_del_oif(up
->channel_oil
,
1146 PIM_OIF_FLAG_PROTO_PIM
);
1150 pim_zebra_zclient_update (struct vty
*vty
)
1152 vty_out(vty
, "Zclient update socket: ");
1155 vty_out(vty
, "%d failures=%d%s", zclient
->sock
,
1156 zclient
->fail
, VTY_NEWLINE
);
1159 vty_out(vty
, "<null zclient>%s", VTY_NEWLINE
);
1163 struct zclient
*pim_zebra_zclient_get (void)