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
22 #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
) {
83 "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
84 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, vrf_id
,
85 (long)ifp
->flags
, ifp
->metric
, ifp
->mtu
,
86 if_is_operative(ifp
));
89 if (if_is_operative(ifp
))
90 pim_if_addr_add_all(ifp
);
93 * If we are a vrf device that is up, open up the pim_socket for
95 * to incoming pim messages irrelevant if the user has configured us
98 if (pim_if_is_vrf_device(ifp
)) {
99 struct pim_interface
*pim_ifp
;
102 pim_ifp
= pim_if_new(ifp
, 0, 0);
112 static int pim_zebra_if_del(int command
, struct zclient
*zclient
,
113 zebra_size_t length
, vrf_id_t vrf_id
)
115 struct interface
*ifp
;
118 zebra api adds/dels interfaces using the same call
119 interface_add_read below, see comments in lib/zclient.c
121 comments in lib/zclient.c seem to indicate that calling
122 zebra_interface_add_read is the correct call, but that
123 results in an attemted out of bounds read which causes
124 pimd to assert. Other clients use zebra_interface_state_read
125 and it appears to work just fine.
127 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
131 if (PIM_DEBUG_ZEBRA
) {
133 "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
134 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, vrf_id
,
135 (long)ifp
->flags
, ifp
->metric
, ifp
->mtu
,
136 if_is_operative(ifp
));
139 if (!if_is_operative(ifp
))
140 pim_if_addr_del_all(ifp
);
145 static int pim_zebra_if_state_up(int command
, struct zclient
*zclient
,
146 zebra_size_t length
, vrf_id_t vrf_id
)
148 struct interface
*ifp
;
152 zebra api notifies interface up/down events by using the same call
153 zebra_interface_state_read below, see comments in lib/zclient.c
155 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
159 if (PIM_DEBUG_ZEBRA
) {
161 "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
162 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, vrf_id
,
163 (long)ifp
->flags
, ifp
->metric
, ifp
->mtu
,
164 if_is_operative(ifp
));
167 if (if_is_operative(ifp
)) {
169 pim_if_addr_add_all() suffices for bringing up both IGMP and
172 pim_if_addr_add_all(ifp
);
176 * If we have a pimreg device callback and it's for a specific
177 * table set the master appropriately
179 if (sscanf(ifp
->name
, "pimreg%d", &table_id
) == 1) {
181 RB_FOREACH (vrf
, vrf_name_head
, &vrfs_by_name
) {
182 if ((table_id
== vrf
->data
.l
.table_id
)
183 && (ifp
->vrf_id
!= vrf
->vrf_id
)) {
184 struct interface
*master
= if_lookup_by_name(
185 vrf
->name
, vrf
->vrf_id
);
189 "%s: Unable to find Master interface for %s",
190 __PRETTY_FUNCTION__
, vrf
->name
);
193 zclient_interface_set_master(zclient
, master
,
201 static int pim_zebra_if_state_down(int command
, struct zclient
*zclient
,
202 zebra_size_t length
, vrf_id_t vrf_id
)
204 struct interface
*ifp
;
207 zebra api notifies interface up/down events by using the same call
208 zebra_interface_state_read below, see comments in lib/zclient.c
210 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
214 if (PIM_DEBUG_ZEBRA
) {
216 "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d",
217 __PRETTY_FUNCTION__
, ifp
->name
, ifp
->ifindex
, vrf_id
,
218 (long)ifp
->flags
, ifp
->metric
, ifp
->mtu
,
219 if_is_operative(ifp
));
222 if (!if_is_operative(ifp
)) {
223 pim_ifchannel_delete_all(ifp
);
225 pim_if_addr_del_all() suffices for shutting down IGMP,
226 but not for shutting down PIM
228 pim_if_addr_del_all(ifp
);
231 pim_sock_delete() closes the socket, stops read and timer
233 and kills all neighbors.
236 pim_sock_delete(ifp
, "link down");
246 #ifdef PIM_DEBUG_IFADDR_DUMP
247 static void dump_if_address(struct interface
*ifp
)
249 struct connected
*ifc
;
250 struct listnode
*node
;
252 zlog_debug("%s %s: interface %s addresses:", __FILE__
,
253 __PRETTY_FUNCTION__
, ifp
->name
);
255 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
256 struct prefix
*p
= ifc
->address
;
258 if (p
->family
!= AF_INET
)
261 zlog_debug("%s %s: interface %s address %s %s", __FILE__
,
262 __PRETTY_FUNCTION__
, ifp
->name
,
263 inet_ntoa(p
->u
.prefix4
),
264 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
)
271 static int pim_zebra_if_address_add(int command
, struct zclient
*zclient
,
272 zebra_size_t length
, vrf_id_t vrf_id
)
276 struct pim_interface
*pim_ifp
;
279 zebra api notifies address adds/dels events by using the same call
280 interface_add_read below, see comments in lib/zclient.c
282 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
283 will add address to interface list by calling
284 connected_add_by_prefix()
286 c
= zebra_interface_address_read(command
, zclient
->ibuf
, vrf_id
);
290 pim_ifp
= c
->ifp
->info
;
293 if (PIM_DEBUG_ZEBRA
) {
295 prefix2str(p
, buf
, BUFSIZ
);
296 zlog_debug("%s: %s(%u) connected IP address %s flags %u %s",
297 __PRETTY_FUNCTION__
, c
->ifp
->name
, vrf_id
, buf
,
299 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)
303 #ifdef PIM_DEBUG_IFADDR_DUMP
304 dump_if_address(c
->ifp
);
308 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
309 /* trying to add primary address */
311 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
312 if (p
->family
!= AF_INET
313 || primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
314 if (PIM_DEBUG_ZEBRA
) {
315 /* but we had a primary address already */
319 prefix2str(p
, buf
, BUFSIZ
);
322 "%s: %s : forcing secondary flag on %s",
323 __PRETTY_FUNCTION__
, c
->ifp
->name
, buf
);
325 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
331 pim_rp_check_on_if_add(pim_ifp
);
333 if (if_is_loopback(c
->ifp
)) {
334 struct vrf
*vrf
= vrf_lookup_by_id(VRF_DEFAULT
);
335 struct interface
*ifp
;
337 FOR_ALL_INTERFACES (vrf
, ifp
) {
338 if (!if_is_loopback(ifp
) && if_is_operative(ifp
))
339 pim_if_addr_add_all(ifp
);
346 static int pim_zebra_if_address_del(int command
, struct zclient
*client
,
347 zebra_size_t length
, vrf_id_t vrf_id
)
351 struct vrf
*vrf
= vrf_lookup_by_id(vrf_id
);
352 struct pim_instance
*pim
;
359 zebra api notifies address adds/dels events by using the same call
360 interface_add_read below, see comments in lib/zclient.c
362 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
363 will remove address from interface list by calling
364 connected_delete_by_prefix()
366 c
= zebra_interface_address_read(command
, client
->ibuf
, vrf_id
);
371 if (p
->family
== AF_INET
) {
372 if (PIM_DEBUG_ZEBRA
) {
374 prefix2str(p
, buf
, BUFSIZ
);
376 "%s: %s(%u) disconnected IP address %s flags %u %s",
377 __PRETTY_FUNCTION__
, c
->ifp
->name
, vrf_id
, buf
,
379 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)
383 #ifdef PIM_DEBUG_IFADDR_DUMP
384 dump_if_address(c
->ifp
);
388 pim_if_addr_del(c
, 0);
390 pim_i_am_rp_re_evaluate(pim
);
397 static void scan_upstream_rpf_cache(struct pim_instance
*pim
)
399 struct listnode
*up_node
;
400 struct listnode
*up_nextnode
;
401 struct listnode
*node
;
402 struct pim_upstream
*up
;
403 struct interface
*ifp
;
405 for (ALL_LIST_ELEMENTS(pim
->upstream_list
, up_node
, up_nextnode
, up
)) {
406 enum pim_rpf_result rpf_result
;
410 nht_p
.family
= AF_INET
;
411 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
412 nht_p
.u
.prefix4
.s_addr
= up
->upstream_addr
.s_addr
;
413 pim_resolve_upstream_nh(pim
, &nht_p
);
415 old
.source_nexthop
.interface
= up
->rpf
.source_nexthop
.interface
;
416 old
.source_nexthop
.nbr
= up
->rpf
.source_nexthop
.nbr
;
417 rpf_result
= pim_rpf_update(pim
, up
, &old
, 0);
419 if (rpf_result
== PIM_RPF_FAILURE
)
422 if (rpf_result
== PIM_RPF_CHANGED
) {
423 struct pim_neighbor
*nbr
;
425 nbr
= pim_neighbor_find(old
.source_nexthop
.interface
,
426 old
.rpf_addr
.u
.prefix4
);
428 pim_jp_agg_remove_group(nbr
->upstream_jp_agg
,
432 * We have detected a case where we might need
434 * the inherited o_list so do it.
436 if (up
->channel_oil
->oil_inherited_rescan
) {
437 pim_upstream_inherited_olist_decide(pim
, up
);
438 up
->channel_oil
->oil_inherited_rescan
= 0;
441 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
443 * If we come up real fast we can be here
444 * where the mroute has not been installed
447 if (!up
->channel_oil
->installed
)
448 pim_mroute_add(up
->channel_oil
,
449 __PRETTY_FUNCTION__
);
452 * RFC 4601: 4.5.7. Sending (S,G)
453 * Join/Prune Messages
455 * Transitions from Joined State
457 * RPF'(S,G) changes not due to an Assert
459 * The upstream (S,G) state machine remains
460 * in Joined state. Send Join(S,G) to the new
461 * upstream neighbor, which is the new value
462 * of RPF'(S,G). Send Prune(S,G) to the old
463 * upstream neighbor, which is the old value
464 * of RPF'(S,G). Set the Join Timer (JT) to
465 * expire after t_periodic seconds.
467 pim_jp_agg_switch_interface(&old
, &up
->rpf
, up
);
469 pim_upstream_join_timer_restart(up
, &old
);
470 } /* up->join_state == PIM_UPSTREAM_JOINED */
472 /* FIXME can join_desired actually be changed by
474 returning PIM_RPF_CHANGED ? */
475 pim_upstream_update_join_desired(pim
, up
);
477 } /* PIM_RPF_CHANGED */
479 } /* for (qpim_upstream_list) */
481 FOR_ALL_INTERFACES (pim
->vrf
, ifp
)
483 struct pim_interface
*pim_ifp
= ifp
->info
;
484 struct pim_iface_upstream_switch
*us
;
486 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->upstream_switch_list
,
490 rpf
.source_nexthop
.interface
= ifp
;
491 rpf
.rpf_addr
.u
.prefix4
= us
->address
;
492 pim_joinprune_send(&rpf
, us
->us
);
493 pim_jp_agg_clear_group(us
->us
);
498 void pim_scan_individual_oil(struct channel_oil
*c_oil
, int in_vif_index
)
500 struct in_addr vif_source
;
501 int input_iface_vif_index
;
504 if (!pim_rp_set_upstream_addr(c_oil
->pim
, &vif_source
,
505 c_oil
->oil
.mfcc_origin
,
506 c_oil
->oil
.mfcc_mcastgrp
))
510 input_iface_vif_index
= in_vif_index
;
512 struct prefix src
, grp
;
514 src
.family
= AF_INET
;
515 src
.prefixlen
= IPV4_MAX_BITLEN
;
516 src
.u
.prefix4
= vif_source
;
517 grp
.family
= AF_INET
;
518 grp
.prefixlen
= IPV4_MAX_BITLEN
;
519 grp
.u
.prefix4
= c_oil
->oil
.mfcc_mcastgrp
;
521 if (PIM_DEBUG_ZEBRA
) {
522 char source_str
[INET_ADDRSTRLEN
];
523 char group_str
[INET_ADDRSTRLEN
];
524 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
,
525 source_str
, sizeof(source_str
));
526 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
,
527 group_str
, sizeof(group_str
));
529 "%s: channel_oil (%s,%s) upstream info is not present.",
530 __PRETTY_FUNCTION__
, source_str
, group_str
);
532 input_iface_vif_index
= pim_ecmp_fib_lookup_if_vif_index(
533 c_oil
->pim
, vif_source
, &src
, &grp
);
536 if (input_iface_vif_index
< 1) {
537 if (PIM_DEBUG_ZEBRA
) {
538 char source_str
[INET_ADDRSTRLEN
];
539 char group_str
[INET_ADDRSTRLEN
];
540 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
,
541 source_str
, sizeof(source_str
));
542 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
,
543 group_str
, sizeof(group_str
));
545 "%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
546 __FILE__
, __PRETTY_FUNCTION__
,
547 c_oil
->oil
.mfcc_parent
, source_str
, group_str
);
549 pim_mroute_del(c_oil
, __PRETTY_FUNCTION__
);
553 if (input_iface_vif_index
== c_oil
->oil
.mfcc_parent
) {
554 if (!c_oil
->installed
)
555 pim_mroute_add(c_oil
, __PRETTY_FUNCTION__
);
561 if (PIM_DEBUG_ZEBRA
) {
562 struct interface
*old_iif
= pim_if_find_by_vif_index(
563 c_oil
->pim
, c_oil
->oil
.mfcc_parent
);
564 struct interface
*new_iif
= pim_if_find_by_vif_index(
565 c_oil
->pim
, input_iface_vif_index
);
566 char source_str
[INET_ADDRSTRLEN
];
567 char group_str
[INET_ADDRSTRLEN
];
568 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
,
570 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
,
573 "%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
574 __FILE__
, __PRETTY_FUNCTION__
, source_str
, group_str
,
575 (old_iif
) ? old_iif
->name
: "<old_iif?>",
576 c_oil
->oil
.mfcc_parent
,
577 (new_iif
) ? new_iif
->name
: "<new_iif?>",
578 input_iface_vif_index
);
581 /* new iif loops to existing oif ? */
582 if (c_oil
->oil
.mfcc_ttls
[input_iface_vif_index
]) {
583 struct interface
*new_iif
= pim_if_find_by_vif_index(
584 c_oil
->pim
, input_iface_vif_index
);
586 if (PIM_DEBUG_ZEBRA
) {
587 char source_str
[INET_ADDRSTRLEN
];
588 char group_str
[INET_ADDRSTRLEN
];
589 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
,
590 source_str
, sizeof(source_str
));
591 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
,
592 group_str
, sizeof(group_str
));
594 "%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
595 __FILE__
, __PRETTY_FUNCTION__
, source_str
,
597 (new_iif
) ? new_iif
->name
: "<new_iif?>",
598 input_iface_vif_index
);
602 /* update iif vif_index */
603 old_vif_index
= c_oil
->oil
.mfcc_parent
;
604 c_oil
->oil
.mfcc_parent
= input_iface_vif_index
;
606 /* update kernel multicast forwarding cache (MFC) */
607 if (pim_mroute_add(c_oil
, __PRETTY_FUNCTION__
)) {
608 if (PIM_DEBUG_MROUTE
) {
609 /* just log warning */
610 struct interface
*old_iif
= pim_if_find_by_vif_index(
611 c_oil
->pim
, old_vif_index
);
612 struct interface
*new_iif
= pim_if_find_by_vif_index(
613 c_oil
->pim
, input_iface_vif_index
);
614 char source_str
[INET_ADDRSTRLEN
];
615 char group_str
[INET_ADDRSTRLEN
];
616 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
,
617 source_str
, sizeof(source_str
));
618 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
,
619 group_str
, sizeof(group_str
));
621 "%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
622 __FILE__
, __PRETTY_FUNCTION__
, source_str
,
624 old_iif
? old_iif
->name
: "<old_iif?>",
625 c_oil
->oil
.mfcc_parent
,
626 new_iif
? new_iif
->name
: "<new_iif?>",
627 input_iface_vif_index
);
632 void pim_scan_oil(struct pim_instance
*pim
)
634 struct listnode
*node
;
635 struct listnode
*nextnode
;
636 struct channel_oil
*c_oil
;
640 pim
->scan_oil_last
= pim_time_monotonic_sec();
641 ++pim
->scan_oil_events
;
643 for (ALL_LIST_ELEMENTS(pim
->channel_oil_list
, node
, nextnode
, c_oil
)) {
644 if (c_oil
->up
&& c_oil
->up
->rpf
.source_nexthop
.interface
) {
645 ifindex
= c_oil
->up
->rpf
.source_nexthop
648 pim_if_find_vifindex_by_ifindex(pim
, ifindex
);
649 /* Pass Current selected NH vif index to mroute
652 pim_scan_individual_oil(c_oil
, vif_index
);
654 pim_scan_individual_oil(c_oil
, 0);
658 static int on_rpf_cache_refresh(struct thread
*t
)
660 struct pim_instance
*pim
= THREAD_ARG(t
);
662 /* update PIM protocol state */
663 scan_upstream_rpf_cache(pim
);
665 /* update kernel multicast forwarding cache (MFC) */
668 pim
->rpf_cache_refresh_last
= pim_time_monotonic_sec();
669 ++pim
->rpf_cache_refresh_events
;
671 // It is called as part of pim_neighbor_add
676 void sched_rpf_cache_refresh(struct pim_instance
*pim
)
678 ++pim
->rpf_cache_refresh_requests
;
680 pim_rpf_set_refresh_time(pim
);
682 if (pim
->rpf_cache_refresher
) {
683 /* Refresh timer is already running */
687 /* Start refresh timer */
689 if (PIM_DEBUG_ZEBRA
) {
690 zlog_debug("%s: triggering %ld msec timer", __PRETTY_FUNCTION__
,
691 qpim_rpf_cache_refresh_delay_msec
);
694 thread_add_timer_msec(master
, on_rpf_cache_refresh
, pim
,
695 qpim_rpf_cache_refresh_delay_msec
,
696 &pim
->rpf_cache_refresher
);
699 static void pim_zebra_connected(struct zclient
*zclient
)
701 /* Send the client registration */
702 bfd_client_sendmsg(zclient
, ZEBRA_BFD_CLIENT_REGISTER
);
704 zclient_send_reg_requests(zclient
, pimg
->vrf_id
);
707 void pim_zebra_init(void)
711 /* Socket for receiving updates from Zebra daemon */
712 zclient
= zclient_new_notify(master
, &zclient_options_default
);
714 zclient
->zebra_connected
= pim_zebra_connected
;
715 zclient
->router_id_update
= pim_router_id_update_zebra
;
716 zclient
->interface_add
= pim_zebra_if_add
;
717 zclient
->interface_delete
= pim_zebra_if_del
;
718 zclient
->interface_up
= pim_zebra_if_state_up
;
719 zclient
->interface_down
= pim_zebra_if_state_down
;
720 zclient
->interface_address_add
= pim_zebra_if_address_add
;
721 zclient
->interface_address_delete
= pim_zebra_if_address_del
;
722 zclient
->nexthop_update
= pim_parse_nexthop_update
;
724 zclient_init(zclient
, ZEBRA_ROUTE_PIM
, 0, &pimd_privs
);
725 if (PIM_DEBUG_PIM_TRACE
) {
726 zlog_info("zclient_init cleared redistribution request");
729 /* Request all redistribution */
730 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
731 if (i
== zclient
->redist_default
)
733 vrf_bitmap_set(zclient
->redist
[AFI_IP
][i
], pimg
->vrf_id
);
735 if (PIM_DEBUG_PIM_TRACE
) {
736 zlog_debug("%s: requesting redistribution for %s (%i)",
737 __PRETTY_FUNCTION__
, zebra_route_string(i
),
742 /* Request default information */
743 zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD
, zclient
,
746 if (PIM_DEBUG_PIM_TRACE
) {
747 zlog_info("%s: requesting default information redistribution",
748 __PRETTY_FUNCTION__
);
750 zlog_notice("%s: zclient update socket initialized",
751 __PRETTY_FUNCTION__
);
754 zclient_lookup_new();
757 void igmp_anysource_forward_start(struct pim_instance
*pim
,
758 struct igmp_group
*group
)
760 struct igmp_source
*source
;
761 struct in_addr src_addr
= {.s_addr
= 0};
762 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
763 zassert(group
->group_filtermode_isexcl
);
764 zassert(listcount(group
->group_source_list
) < 1);
766 source
= source_new(group
, src_addr
);
768 zlog_warn("%s: Failure to create * source",
769 __PRETTY_FUNCTION__
);
773 igmp_source_forward_start(pim
, source
);
776 void igmp_anysource_forward_stop(struct igmp_group
*group
)
778 struct igmp_source
*source
;
779 struct in_addr star
= {.s_addr
= 0};
781 source
= igmp_find_source_by_addr(group
, star
);
783 igmp_source_forward_stop(source
);
786 static void igmp_source_forward_reevaluate_one(struct pim_instance
*pim
,
787 struct igmp_source
*source
)
790 struct igmp_group
*group
= source
->source_group
;
791 struct pim_ifchannel
*ch
;
793 if ((source
->source_addr
.s_addr
!= INADDR_ANY
)
794 || !IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
))
797 memset(&sg
, 0, sizeof(struct prefix_sg
));
798 sg
.src
= source
->source_addr
;
799 sg
.grp
= group
->group_addr
;
801 ch
= pim_ifchannel_find(group
->group_igmp_sock
->interface
, &sg
);
802 if (pim_is_grp_ssm(pim
, group
->group_addr
)) {
803 /* If SSM group withdraw local membership */
805 && (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_INCLUDE
)) {
806 if (PIM_DEBUG_PIM_EVENTS
)
808 "local membership del for %s as G is now SSM",
809 pim_str_sg_dump(&sg
));
810 pim_ifchannel_local_membership_del(
811 group
->group_igmp_sock
->interface
, &sg
);
814 /* If ASM group add local membership */
816 || (ch
->local_ifmembership
== PIM_IFMEMBERSHIP_NOINFO
)) {
817 if (PIM_DEBUG_PIM_EVENTS
)
819 "local membership add for %s as G is now ASM",
820 pim_str_sg_dump(&sg
));
821 pim_ifchannel_local_membership_add(
822 group
->group_igmp_sock
->interface
, &sg
);
827 void igmp_source_forward_reevaluate_all(struct pim_instance
*pim
)
829 struct interface
*ifp
;
831 FOR_ALL_INTERFACES (pim
->vrf
, ifp
) {
832 struct pim_interface
*pim_ifp
= ifp
->info
;
833 struct listnode
*sock_node
;
834 struct igmp_sock
*igmp
;
839 /* scan igmp sockets */
840 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->igmp_socket_list
, sock_node
,
842 struct listnode
*grpnode
;
843 struct igmp_group
*grp
;
845 /* scan igmp groups */
846 for (ALL_LIST_ELEMENTS_RO(igmp
->igmp_group_list
,
848 struct listnode
*srcnode
;
849 struct igmp_source
*src
;
851 /* scan group sources */
852 for (ALL_LIST_ELEMENTS_RO(
853 grp
->group_source_list
, srcnode
,
855 igmp_source_forward_reevaluate_one(pim
,
857 } /* scan group sources */
858 } /* scan igmp groups */
859 } /* scan igmp sockets */
860 } /* scan interfaces */
863 void igmp_source_forward_start(struct pim_instance
*pim
,
864 struct igmp_source
*source
)
866 struct igmp_group
*group
;
869 int input_iface_vif_index
= 0;
871 memset(&sg
, 0, sizeof(struct prefix_sg
));
872 sg
.src
= source
->source_addr
;
873 sg
.grp
= source
->source_group
->group_addr
;
875 if (PIM_DEBUG_IGMP_TRACE
) {
877 "%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
878 __PRETTY_FUNCTION__
, pim_str_sg_dump(&sg
),
879 source
->source_group
->group_igmp_sock
->fd
,
880 source
->source_group
->group_igmp_sock
->interface
->name
,
881 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
884 /* Prevent IGMP interface from installing multicast route multiple
886 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
890 group
= source
->source_group
;
892 if (!source
->source_channel_oil
) {
893 struct in_addr vif_source
;
894 struct pim_interface
*pim_oif
;
895 struct prefix nht_p
, src
, grp
;
896 struct pim_nexthop_cache out_pnc
;
897 struct pim_nexthop nexthop
;
898 struct pim_upstream
*up
= NULL
;
900 if (!pim_rp_set_upstream_addr(pim
, &vif_source
,
901 source
->source_addr
, sg
.grp
))
904 /* Register addr with Zebra NHT */
905 nht_p
.family
= AF_INET
;
906 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
907 nht_p
.u
.prefix4
= vif_source
;
908 memset(&out_pnc
, 0, sizeof(struct pim_nexthop_cache
));
910 src
.family
= AF_INET
;
911 src
.prefixlen
= IPV4_MAX_BITLEN
;
912 src
.u
.prefix4
= vif_source
; // RP or Src address
913 grp
.family
= AF_INET
;
914 grp
.prefixlen
= IPV4_MAX_BITLEN
;
915 grp
.u
.prefix4
= sg
.grp
;
917 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, NULL
,
919 if (out_pnc
.nexthop_num
) {
920 up
= pim_upstream_find(pim
, &sg
);
921 memset(&nexthop
, 0, sizeof(nexthop
));
924 &up
->rpf
.source_nexthop
,
925 sizeof(struct pim_nexthop
));
926 pim_ecmp_nexthop_search(pim
, &out_pnc
, &nexthop
,
928 if (nexthop
.interface
)
929 input_iface_vif_index
=
930 pim_if_find_vifindex_by_ifindex(
932 nexthop
.interface
->ifindex
);
934 if (PIM_DEBUG_ZEBRA
) {
935 char buf1
[INET_ADDRSTRLEN
];
936 char buf2
[INET_ADDRSTRLEN
];
937 pim_inet4_dump("<source?>",
938 nht_p
.u
.prefix4
, buf1
,
940 pim_inet4_dump("<source?>",
944 "%s: NHT Nexthop not found for addr %s grp %s",
945 __PRETTY_FUNCTION__
, buf1
,
950 input_iface_vif_index
=
951 pim_ecmp_fib_lookup_if_vif_index(
952 pim
, vif_source
, &src
, &grp
);
954 if (PIM_DEBUG_ZEBRA
) {
955 char buf2
[INET_ADDRSTRLEN
];
956 pim_inet4_dump("<source?>", vif_source
, buf2
,
958 zlog_debug("%s: NHT %s vif_source %s vif_index:%d ",
959 __PRETTY_FUNCTION__
, pim_str_sg_dump(&sg
),
960 buf2
, input_iface_vif_index
);
963 if (input_iface_vif_index
< 1) {
964 if (PIM_DEBUG_IGMP_TRACE
) {
965 char source_str
[INET_ADDRSTRLEN
];
966 pim_inet4_dump("<source?>", source
->source_addr
,
967 source_str
, sizeof(source_str
));
969 "%s %s: could not find input interface for source %s",
970 __FILE__
, __PRETTY_FUNCTION__
,
977 Protect IGMP against adding looped MFC entries created by both
978 source and receiver attached to the same interface. See TODO
982 source
->source_group
->group_igmp_sock
->interface
->info
;
984 if (PIM_DEBUG_IGMP_TRACE
) {
986 "%s: multicast not enabled on oif=%s ?",
988 source
->source_group
->group_igmp_sock
994 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
995 /* ignore request for looped MFC entry */
996 if (PIM_DEBUG_IGMP_TRACE
) {
998 "%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
1000 pim_str_sg_dump(&sg
),
1001 source
->source_group
->group_igmp_sock
1003 source
->source_group
->group_igmp_sock
1005 input_iface_vif_index
);
1010 source
->source_channel_oil
=
1011 pim_channel_oil_add(pim
, &sg
, input_iface_vif_index
);
1012 if (!source
->source_channel_oil
) {
1013 if (PIM_DEBUG_IGMP_TRACE
) {
1015 "%s %s: could not create OIL for channel (S,G)=%s",
1016 __FILE__
, __PRETTY_FUNCTION__
,
1017 pim_str_sg_dump(&sg
));
1023 result
= pim_channel_add_oif(source
->source_channel_oil
,
1024 group
->group_igmp_sock
->interface
,
1025 PIM_OIF_FLAG_PROTO_IGMP
);
1027 if (PIM_DEBUG_MROUTE
) {
1028 zlog_warn("%s: add_oif() failed with return=%d",
1035 Feed IGMPv3-gathered local membership information into PIM
1036 per-interface (S,G) state.
1038 if (!pim_ifchannel_local_membership_add(
1039 group
->group_igmp_sock
->interface
, &sg
)) {
1040 if (PIM_DEBUG_MROUTE
)
1041 zlog_warn("%s: Failure to add local membership for %s",
1042 __PRETTY_FUNCTION__
, pim_str_sg_dump(&sg
));
1046 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1050 igmp_source_forward_stop: stop fowarding, but keep the source
1051 igmp_source_delete: stop fowarding, and delete the source
1053 void igmp_source_forward_stop(struct igmp_source
*source
)
1055 struct igmp_group
*group
;
1056 struct prefix_sg sg
;
1059 memset(&sg
, 0, sizeof(struct prefix_sg
));
1060 sg
.src
= source
->source_addr
;
1061 sg
.grp
= source
->source_group
->group_addr
;
1063 if (PIM_DEBUG_IGMP_TRACE
) {
1065 "%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
1066 __PRETTY_FUNCTION__
, pim_str_sg_dump(&sg
),
1067 source
->source_group
->group_igmp_sock
->fd
,
1068 source
->source_group
->group_igmp_sock
->interface
->name
,
1069 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1072 /* Prevent IGMP interface from removing multicast route multiple
1074 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1078 group
= source
->source_group
;
1081 It appears that in certain circumstances that
1082 igmp_source_forward_stop is called when IGMP forwarding
1083 was not enabled in oif_flags for this outgoing interface.
1084 Possibly because of multiple calls. When that happens, we
1085 enter the below if statement and this function returns early
1086 which in turn triggers the calling function to assert.
1087 Making the call to pim_channel_del_oif and ignoring the return code
1088 fixes the issue without ill effect, similar to
1089 pim_forward_stop below.
1091 result
= pim_channel_del_oif(source
->source_channel_oil
,
1092 group
->group_igmp_sock
->interface
,
1093 PIM_OIF_FLAG_PROTO_IGMP
);
1095 if (PIM_DEBUG_IGMP_TRACE
)
1097 "%s: pim_channel_del_oif() failed with return=%d",
1103 Feed IGMPv3-gathered local membership information into PIM
1104 per-interface (S,G) state.
1106 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1109 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1112 void pim_forward_start(struct pim_ifchannel
*ch
)
1114 struct pim_upstream
*up
= ch
->upstream
;
1115 uint32_t mask
= PIM_OIF_FLAG_PROTO_PIM
;
1116 int input_iface_vif_index
= 0;
1117 struct pim_instance
*pim
;
1118 struct pim_interface
*pim_ifp
;
1120 pim_ifp
= ch
->interface
->info
;
1123 if (PIM_DEBUG_PIM_TRACE
) {
1124 char source_str
[INET_ADDRSTRLEN
];
1125 char group_str
[INET_ADDRSTRLEN
];
1126 char upstream_str
[INET_ADDRSTRLEN
];
1128 pim_inet4_dump("<source?>", ch
->sg
.src
, source_str
,
1129 sizeof(source_str
));
1130 pim_inet4_dump("<group?>", ch
->sg
.grp
, group_str
,
1132 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
,
1133 sizeof(upstream_str
));
1134 zlog_debug("%s: (S,G)=(%s,%s) oif=%s (%s)", __PRETTY_FUNCTION__
,
1135 source_str
, group_str
, ch
->interface
->name
,
1139 /* Resolve IIF for upstream as mroute_del sets mfcc_parent to MAXVIFS,
1140 as part of mroute_del called by pim_forward_stop.
1142 if (!up
->channel_oil
1144 && up
->channel_oil
->oil
.mfcc_parent
>= MAXVIFS
)) {
1145 struct prefix nht_p
, src
, grp
;
1146 struct pim_nexthop_cache out_pnc
;
1148 /* Register addr with Zebra NHT */
1149 nht_p
.family
= AF_INET
;
1150 nht_p
.prefixlen
= IPV4_MAX_BITLEN
;
1151 nht_p
.u
.prefix4
.s_addr
= up
->upstream_addr
.s_addr
;
1152 grp
.family
= AF_INET
;
1153 grp
.prefixlen
= IPV4_MAX_BITLEN
;
1154 grp
.u
.prefix4
= up
->sg
.grp
;
1155 memset(&out_pnc
, 0, sizeof(struct pim_nexthop_cache
));
1157 if (pim_find_or_track_nexthop(pim
, &nht_p
, NULL
, NULL
,
1159 if (out_pnc
.nexthop_num
) {
1160 src
.family
= AF_INET
;
1161 src
.prefixlen
= IPV4_MAX_BITLEN
;
1163 up
->upstream_addr
; // RP or Src address
1164 grp
.family
= AF_INET
;
1165 grp
.prefixlen
= IPV4_MAX_BITLEN
;
1166 grp
.u
.prefix4
= up
->sg
.grp
;
1167 // Compute PIM RPF using Cached nexthop
1168 if (pim_ecmp_nexthop_search(
1170 &up
->rpf
.source_nexthop
, &src
, &grp
,
1172 input_iface_vif_index
=
1173 pim_if_find_vifindex_by_ifindex(
1175 up
->rpf
.source_nexthop
1176 .interface
->ifindex
);
1178 if (PIM_DEBUG_TRACE
)
1180 "%s: Nexthop selection failed for %s ",
1181 __PRETTY_FUNCTION__
,
1185 if (PIM_DEBUG_ZEBRA
) {
1186 char buf1
[INET_ADDRSTRLEN
];
1187 char buf2
[INET_ADDRSTRLEN
];
1188 pim_inet4_dump("<source?>",
1189 nht_p
.u
.prefix4
, buf1
,
1191 pim_inet4_dump("<source?>",
1192 grp
.u
.prefix4
, buf2
,
1195 "%s: NHT pnc is NULL for addr %s grp %s",
1196 __PRETTY_FUNCTION__
, buf1
,
1201 input_iface_vif_index
=
1202 pim_ecmp_fib_lookup_if_vif_index(
1203 pim
, up
->upstream_addr
, &src
, &grp
);
1205 if (input_iface_vif_index
< 1) {
1206 if (PIM_DEBUG_PIM_TRACE
) {
1207 char source_str
[INET_ADDRSTRLEN
];
1208 pim_inet4_dump("<source?>", up
->sg
.src
,
1209 source_str
, sizeof(source_str
));
1211 "%s %s: could not find input interface for source %s",
1212 __FILE__
, __PRETTY_FUNCTION__
,
1217 if (PIM_DEBUG_TRACE
) {
1218 struct interface
*in_intf
= pim_if_find_by_vif_index(
1219 pim
, input_iface_vif_index
);
1221 "%s: Update channel_oil IIF %s VIFI %d entry %s ",
1222 __PRETTY_FUNCTION__
,
1223 in_intf
? in_intf
->name
: "NIL",
1224 input_iface_vif_index
, up
->sg_str
);
1226 up
->channel_oil
= pim_channel_oil_add(pim
, &up
->sg
,
1227 input_iface_vif_index
);
1228 if (!up
->channel_oil
) {
1229 if (PIM_DEBUG_PIM_TRACE
)
1231 "%s %s: could not create OIL for channel (S,G)=%s",
1232 __FILE__
, __PRETTY_FUNCTION__
,
1238 if (up
->flags
& PIM_UPSTREAM_FLAG_MASK_SRC_IGMP
)
1239 mask
= PIM_OIF_FLAG_PROTO_IGMP
;
1241 pim_channel_add_oif(up
->channel_oil
, ch
->interface
, mask
);
1244 void pim_forward_stop(struct pim_ifchannel
*ch
, bool install_it
)
1246 struct pim_upstream
*up
= ch
->upstream
;
1248 if (PIM_DEBUG_PIM_TRACE
) {
1249 zlog_debug("%s: (S,G)=%s oif=%s install_it: %d installed: %d",
1250 __PRETTY_FUNCTION__
, ch
->sg_str
, ch
->interface
->name
,
1251 install_it
, up
->channel_oil
->installed
);
1254 pim_channel_del_oif(up
->channel_oil
, ch
->interface
,
1255 PIM_OIF_FLAG_PROTO_PIM
);
1257 if (install_it
&& !up
->channel_oil
->installed
)
1258 pim_mroute_add(up
->channel_oil
, __PRETTY_FUNCTION__
);
1261 void pim_zebra_zclient_update(struct vty
*vty
)
1263 vty_out(vty
, "Zclient update socket: ");
1266 vty_out(vty
, "%d failures=%d\n", zclient
->sock
, zclient
->fail
);
1268 vty_out(vty
, "<null zclient>\n");
1272 struct zclient
*pim_zebra_zclient_get(void)