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,
24 #include "zebra/rib.h"
37 #include "pim_zebra.h"
38 #include "pim_iface.h"
44 #include "pim_zlookup.h"
45 #include "pim_ifchannel.h"
47 #include "pim_igmpv3.h"
49 #undef PIM_DEBUG_IFADDR_DUMP
50 #define PIM_DEBUG_IFADDR_DUMP
52 static int fib_lookup_if_vif_index(struct in_addr addr
);
53 static int del_oif(struct channel_oil
*channel_oil
,
54 struct interface
*oif
,
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
)) {
178 pim_if_addr_del_all() suffices for shutting down IGMP,
179 but not for shutting down PIM
181 pim_if_addr_del_all(ifp
);
184 pim_sock_delete() closes the socket, stops read and timer threads,
185 and kills all neighbors.
188 pim_sock_delete(ifp
, "link down");
195 #ifdef PIM_DEBUG_IFADDR_DUMP
196 static void dump_if_address(struct interface
*ifp
)
198 struct connected
*ifc
;
199 struct listnode
*node
;
201 zlog_debug("%s %s: interface %s addresses:",
202 __FILE__
, __PRETTY_FUNCTION__
,
205 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
206 struct prefix
*p
= ifc
->address
;
208 if (p
->family
!= AF_INET
)
211 zlog_debug("%s %s: interface %s address %s %s",
212 __FILE__
, __PRETTY_FUNCTION__
,
214 inet_ntoa(p
->u
.prefix4
),
215 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
216 "secondary" : "primary");
221 static int pim_zebra_if_address_add(int command
, struct zclient
*zclient
,
222 zebra_size_t length
, vrf_id_t vrf_id
)
226 struct in_addr old
= { .s_addr
= 0 };
229 zebra api notifies address adds/dels events by using the same call
230 interface_add_read below, see comments in lib/zclient.c
232 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
233 will add address to interface list by calling
234 connected_add_by_prefix()
236 c
= zebra_interface_address_read(command
, zclient
->ibuf
, vrf_id
);
242 if (PIM_DEBUG_ZEBRA
) {
244 prefix2str(p
, buf
, BUFSIZ
);
245 zlog_debug("%s: %s connected IP address %s flags %u %s",
247 c
->ifp
->name
, buf
, c
->flags
,
248 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
250 #ifdef PIM_DEBUG_IFADDR_DUMP
251 dump_if_address(c
->ifp
);
255 if (p
->family
!= AF_INET
)
257 struct pim_interface
*pim_ifp
= c
->ifp
->info
;
258 struct listnode
*cnode
;
259 struct connected
*conn
;
262 for (ALL_LIST_ELEMENTS_RO (c
->ifp
->connected
, cnode
, conn
))
264 if (conn
->address
->family
== AF_INET
)
267 if (!v4addrs
&& pim_ifp
)
269 pim_ifp
->primary_address
= pim_find_primary_addr (c
->ifp
);
270 pim_if_addr_add_all (c
->ifp
);
271 pim_if_add_vif (c
->ifp
);
276 pim_rp_check_rp (old
, p
->u
.prefix4
);
278 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
279 /* trying to add primary address */
281 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
282 if (primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
283 if (PIM_DEBUG_ZEBRA
) {
284 /* but we had a primary address already */
289 prefix2str(p
, buf
, BUFSIZ
);
290 pim_inet4_dump("<old?>", primary_addr
, old
, sizeof(old
));
292 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
294 c
->ifp
->name
, old
, buf
);
296 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
302 if (if_is_loopback (c
->ifp
))
304 struct listnode
*ifnode
;
305 struct interface
*ifp
;
307 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
))
309 if (!if_is_loopback (ifp
) && if_is_operative (ifp
))
310 pim_if_addr_add_all (ifp
);
317 static int pim_zebra_if_address_del(int command
, struct zclient
*client
,
318 zebra_size_t length
, vrf_id_t vrf_id
)
322 struct in_addr
new = { .s_addr
= 0 };
325 zebra api notifies address adds/dels events by using the same call
326 interface_add_read below, see comments in lib/zclient.c
328 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
329 will remove address from interface list by calling
330 connected_delete_by_prefix()
332 c
= zebra_interface_address_read(command
, client
->ibuf
, vrf_id
);
337 if (p
->family
!= AF_INET
)
340 if (PIM_DEBUG_ZEBRA
) {
342 prefix2str(p
, buf
, BUFSIZ
);
343 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
345 c
->ifp
->name
, buf
, c
->flags
,
346 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
348 #ifdef PIM_DEBUG_IFADDR_DUMP
349 dump_if_address(c
->ifp
);
353 pim_rp_check_rp (p
->u
.prefix4
, new);
354 pim_if_addr_del(c
, 0);
359 static void scan_upstream_rpf_cache()
361 struct listnode
*up_node
;
362 struct listnode
*up_nextnode
;
363 struct pim_upstream
*up
;
365 for (ALL_LIST_ELEMENTS(qpim_upstream_list
, up_node
, up_nextnode
, up
)) {
366 struct in_addr old_rpf_addr
;
367 struct interface
*old_interface
;
368 enum pim_rpf_result rpf_result
;
370 old_interface
= up
->rpf
.source_nexthop
.interface
;
371 rpf_result
= pim_rpf_update(up
, &old_rpf_addr
);
372 if (rpf_result
== PIM_RPF_FAILURE
)
375 if (rpf_result
== PIM_RPF_CHANGED
) {
377 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
379 * If we come up real fast we can be here
380 * where the mroute has not been installed
383 if (up
->channel_oil
&& !up
->channel_oil
->installed
)
384 pim_mroute_add (up
->channel_oil
);
387 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
389 Transitions from Joined State
391 RPF'(S,G) changes not due to an Assert
393 The upstream (S,G) state machine remains in Joined
394 state. Send Join(S,G) to the new upstream neighbor, which is
395 the new value of RPF'(S,G). Send Prune(S,G) to the old
396 upstream neighbor, which is the old value of RPF'(S,G). Set
397 the Join Timer (JT) to expire after t_periodic seconds.
401 /* send Prune(S,G) to the old upstream neighbor */
402 pim_joinprune_send(old_interface
, old_rpf_addr
,
403 &up
->sg
, 0 /* prune */);
405 /* send Join(S,G) to the current upstream neighbor */
406 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
407 up
->rpf
.rpf_addr
.u
.prefix4
,
411 pim_upstream_join_timer_restart(up
);
412 } /* up->join_state == PIM_UPSTREAM_JOINED */
414 /* FIXME can join_desired actually be changed by pim_rpf_update()
415 returning PIM_RPF_CHANGED ? */
416 pim_upstream_update_join_desired(up
);
418 } /* PIM_RPF_CHANGED */
420 } /* for (qpim_upstream_list) */
425 pim_scan_individual_oil (struct channel_oil
*c_oil
)
427 struct in_addr vif_source
;
428 int input_iface_vif_index
;
431 if (!pim_rp_set_upstream_addr (&vif_source
, c_oil
->oil
.mfcc_origin
, c_oil
->oil
.mfcc_mcastgrp
))
434 input_iface_vif_index
= fib_lookup_if_vif_index (vif_source
);
435 if (input_iface_vif_index
< 1)
439 char source_str
[100];
441 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
442 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
443 zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
444 __FILE__
, __PRETTY_FUNCTION__
, c_oil
->oil
.mfcc_parent
,
445 source_str
, group_str
);
447 pim_mroute_del (c_oil
);
451 if (input_iface_vif_index
== c_oil
->oil
.mfcc_parent
)
459 struct interface
*old_iif
= pim_if_find_by_vif_index(c_oil
->oil
.mfcc_parent
);
460 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
461 char source_str
[100];
463 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
464 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
465 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
466 __FILE__
, __PRETTY_FUNCTION__
,
467 source_str
, group_str
,
468 old_iif
->name
, c_oil
->oil
.mfcc_parent
,
469 new_iif
->name
, input_iface_vif_index
);
472 /* new iif loops to existing oif ? */
473 if (c_oil
->oil
.mfcc_ttls
[input_iface_vif_index
])
475 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
477 if (PIM_DEBUG_ZEBRA
) {
478 char source_str
[100];
480 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
481 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
482 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
483 __FILE__
, __PRETTY_FUNCTION__
,
484 source_str
, group_str
,
485 new_iif
->name
, input_iface_vif_index
);
488 del_oif(c_oil
, new_iif
, PIM_OIF_FLAG_PROTO_ANY
);
491 /* update iif vif_index */
492 old_vif_index
= c_oil
->oil
.mfcc_parent
;
493 c_oil
->oil
.mfcc_parent
= input_iface_vif_index
;
495 /* update kernel multicast forwarding cache (MFC) */
496 if (pim_mroute_add(c_oil
))
498 /* just log warning */
499 struct interface
*old_iif
= pim_if_find_by_vif_index(old_vif_index
);
500 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
501 char source_str
[100];
503 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
504 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
505 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
506 __FILE__
, __PRETTY_FUNCTION__
,
507 source_str
, group_str
,
508 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
509 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
515 struct listnode
*node
;
516 struct listnode
*nextnode
;
517 struct channel_oil
*c_oil
;
519 qpim_scan_oil_last
= pim_time_monotonic_sec();
520 ++qpim_scan_oil_events
;
522 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list
, node
, nextnode
, c_oil
))
523 pim_scan_individual_oil (c_oil
);
526 static int on_rpf_cache_refresh(struct thread
*t
)
529 zassert(qpim_rpf_cache_refresher
);
531 qpim_rpf_cache_refresher
= 0;
533 /* update PIM protocol state */
534 scan_upstream_rpf_cache();
536 /* update kernel multicast forwarding cache (MFC) */
539 qpim_rpf_cache_refresh_last
= pim_time_monotonic_sec();
540 ++qpim_rpf_cache_refresh_events
;
546 static void sched_rpf_cache_refresh()
548 ++qpim_rpf_cache_refresh_requests
;
550 if (qpim_rpf_cache_refresher
) {
551 /* Refresh timer is already running */
555 /* Start refresh timer */
557 if (PIM_DEBUG_ZEBRA
) {
558 zlog_debug("%s: triggering %ld msec timer",
560 qpim_rpf_cache_refresh_delay_msec
);
563 THREAD_TIMER_MSEC_ON(master
, qpim_rpf_cache_refresher
,
564 on_rpf_cache_refresh
,
565 0, qpim_rpf_cache_refresh_delay_msec
);
568 static int redist_read_ipv4_route(int command
, struct zclient
*zclient
,
569 zebra_size_t length
, vrf_id_t vrf_id
)
572 struct zapi_ipv4 api
;
574 struct in_addr nexthop
;
575 struct prefix_ipv4 p
;
578 if (length
< min_len
) {
579 zlog_warn("%s %s: short buffer: length=%d min=%d",
580 __FILE__
, __PRETTY_FUNCTION__
,
589 /* Type, flags, message. */
590 api
.type
= stream_getc(s
);
591 api
.instance
= stream_getw (s
);
592 api
.flags
= stream_getl(s
);
593 api
.message
= stream_getc(s
);
595 /* IPv4 prefix length. */
596 memset(&p
, 0, sizeof(struct prefix_ipv4
));
598 p
.prefixlen
= stream_getc(s
);
602 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? 5 : 0 +
603 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? 5 : 0 +
604 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? 1 : 0 +
605 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? 4 : 0;
607 if (PIM_DEBUG_ZEBRA
) {
608 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
609 __FILE__
, __PRETTY_FUNCTION__
,
611 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
612 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
613 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
614 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
617 if (length
< min_len
) {
618 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
619 __FILE__
, __PRETTY_FUNCTION__
,
621 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
622 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
623 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
624 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
629 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
631 /* Nexthop, ifindex, distance, metric. */
632 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
633 api
.nexthop_num
= stream_getc(s
);
634 nexthop
.s_addr
= stream_get_ipv4(s
);
636 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
)) {
637 api
.ifindex_num
= stream_getc(s
);
638 ifindex
= stream_getl(s
);
641 api
.distance
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ?
645 api
.metric
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ?
649 if (CHECK_FLAG (api
.message
, ZAPI_MESSAGE_TAG
))
650 api
.tag
= stream_getl (s
);
655 case ZEBRA_REDISTRIBUTE_IPV4_ADD
:
656 if (PIM_DEBUG_ZEBRA
) {
657 char buf
[2][INET_ADDRSTRLEN
];
658 zlog_debug("%s: add %s %s/%d "
659 "nexthop %s ifindex %d metric%s %u distance%s %u",
661 zebra_route_string(api
.type
),
662 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
664 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
666 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
668 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
672 case ZEBRA_REDISTRIBUTE_IPV4_DEL
:
673 if (PIM_DEBUG_ZEBRA
) {
674 char buf
[2][INET_ADDRSTRLEN
];
675 zlog_debug("%s: delete %s %s/%d "
676 "nexthop %s ifindex %d metric%s %u distance%s %u",
678 zebra_route_string(api
.type
),
679 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
681 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
683 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
685 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
690 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__
, command
);
694 sched_rpf_cache_refresh();
701 pim_zebra_connected (struct zclient
*zclient
)
703 zclient_send_reg_requests (zclient
, VRF_DEFAULT
);
705 void pim_zebra_init(char *zebra_sock_path
)
710 zclient_serv_path_set(zebra_sock_path
);
712 #ifdef HAVE_TCP_ZEBRA
713 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT
);
715 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
718 /* Socket for receiving updates from Zebra daemon */
719 qpim_zclient_update
= zclient_new (master
);
721 qpim_zclient_update
->zebra_connected
= pim_zebra_connected
;
722 qpim_zclient_update
->router_id_update
= pim_router_id_update_zebra
;
723 qpim_zclient_update
->interface_add
= pim_zebra_if_add
;
724 qpim_zclient_update
->interface_delete
= pim_zebra_if_del
;
725 qpim_zclient_update
->interface_up
= pim_zebra_if_state_up
;
726 qpim_zclient_update
->interface_down
= pim_zebra_if_state_down
;
727 qpim_zclient_update
->interface_address_add
= pim_zebra_if_address_add
;
728 qpim_zclient_update
->interface_address_delete
= pim_zebra_if_address_del
;
729 qpim_zclient_update
->redistribute_route_ipv4_add
= redist_read_ipv4_route
;
730 qpim_zclient_update
->redistribute_route_ipv4_del
= redist_read_ipv4_route
;
732 zclient_init(qpim_zclient_update
, ZEBRA_ROUTE_PIM
, 0);
733 if (PIM_DEBUG_PIM_TRACE
) {
734 zlog_info("zclient_init cleared redistribution request");
737 zassert(qpim_zclient_update
->redist_default
== ZEBRA_ROUTE_PIM
);
739 /* Request all redistribution */
740 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
741 if (i
== qpim_zclient_update
->redist_default
)
743 vrf_bitmap_set (qpim_zclient_update
->redist
[AFI_IP
][i
], VRF_DEFAULT
);;
744 if (PIM_DEBUG_PIM_TRACE
) {
745 zlog_debug("%s: requesting redistribution for %s (%i)",
746 __PRETTY_FUNCTION__
, zebra_route_string(i
), i
);
750 /* Request default information */
751 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
752 qpim_zclient_update
, VRF_DEFAULT
);
754 if (PIM_DEBUG_PIM_TRACE
) {
755 zlog_info("%s: requesting default information redistribution",
756 __PRETTY_FUNCTION__
);
758 zlog_notice("%s: zclient update socket initialized",
759 __PRETTY_FUNCTION__
);
762 zclient_lookup_new();
765 void igmp_anysource_forward_start(struct igmp_group
*group
)
767 struct igmp_source
*source
;
768 struct in_addr src_addr
= { .s_addr
= 0 };
769 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
770 zassert(group
->group_filtermode_isexcl
);
771 zassert(listcount(group
->group_source_list
) < 1);
773 source
= source_new (group
, src_addr
);
776 zlog_warn ("%s: Failure to create * source", __PRETTY_FUNCTION__
);
780 igmp_source_forward_start (source
);
783 void igmp_anysource_forward_stop(struct igmp_group
*group
)
785 struct igmp_source
*source
;
786 struct in_addr star
= { .s_addr
= 0 };
788 source
= igmp_find_source_by_addr (group
, star
);
790 igmp_source_forward_stop (source
);
793 static int fib_lookup_if_vif_index(struct in_addr addr
)
795 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
798 ifindex_t first_ifindex
;
800 num_ifindex
= zclient_lookup_nexthop(nexthop_tab
,
802 PIM_NEXTHOP_LOOKUP_MAX
);
803 if (num_ifindex
< 1) {
805 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
806 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
807 __FILE__
, __PRETTY_FUNCTION__
,
812 first_ifindex
= nexthop_tab
[0].ifindex
;
814 if (num_ifindex
> 1) {
816 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
817 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
818 __FILE__
, __PRETTY_FUNCTION__
,
819 num_ifindex
, addr_str
, first_ifindex
);
820 /* debug warning only, do not return */
823 if (PIM_DEBUG_ZEBRA
) {
825 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
826 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
827 __FILE__
, __PRETTY_FUNCTION__
,
828 first_ifindex
, ifindex2ifname(first_ifindex
), addr_str
);
831 vif_index
= pim_if_find_vifindex_by_ifindex(first_ifindex
);
835 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
836 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
837 __FILE__
, __PRETTY_FUNCTION__
,
838 vif_index
, addr_str
);
842 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
844 if (vif_index
> qpim_mroute_oif_highest_vif_index
) {
846 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
847 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
848 __FILE__
, __PRETTY_FUNCTION__
,
849 vif_index
, qpim_mroute_oif_highest_vif_index
, addr_str
);
851 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
852 __FILE__
, __PRETTY_FUNCTION__
,
853 ifindex2ifname(vif_index
),
862 static int del_oif(struct channel_oil
*channel_oil
,
863 struct interface
*oif
,
866 struct pim_interface
*pim_ifp
;
869 zassert(channel_oil
);
873 zassert(pim_ifp
->mroute_vif_index
>= 1);
874 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
875 zassert(pim_ifp
->mroute_vif_index
<= qpim_mroute_oif_highest_vif_index
);
877 if (PIM_DEBUG_MROUTE
) {
879 char source_str
[100];
880 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
881 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
882 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
883 __FILE__
, __PRETTY_FUNCTION__
,
884 source_str
, group_str
,
885 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
888 /* Prevent single protocol from unsubscribing same interface from
889 channel (S,G) multiple times */
890 if (!(channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & proto_mask
)) {
892 char source_str
[100];
893 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
894 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
895 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
896 __FILE__
, __PRETTY_FUNCTION__
,
897 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
898 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
899 source_str
, group_str
);
903 /* Mark that protocol is no longer interested in this OIF */
904 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] &= ~proto_mask
;
906 /* Allow multiple protocols to unsubscribe same interface from
907 channel (S,G) multiple times, by silently ignoring requests while
908 there is at least one protocol interested in the channel */
909 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
911 /* Check the OIF keeps existing before returning, and only log
913 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
915 char source_str
[100];
916 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
917 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
918 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
919 __FILE__
, __PRETTY_FUNCTION__
,
920 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
921 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
922 source_str
, group_str
);
928 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
932 char source_str
[100];
933 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
934 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
935 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
936 __FILE__
, __PRETTY_FUNCTION__
,
937 oif
->name
, pim_ifp
->mroute_vif_index
,
938 source_str
, group_str
);
942 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = 0;
944 if (pim_mroute_add(channel_oil
)) {
946 char source_str
[100];
947 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
948 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
949 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
950 __FILE__
, __PRETTY_FUNCTION__
,
951 oif
->name
, pim_ifp
->mroute_vif_index
,
952 source_str
, group_str
);
954 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
958 --channel_oil
->oil_size
;
960 if (channel_oil
->oil_size
< 1) {
961 if (pim_mroute_del(channel_oil
)) {
962 /* just log a warning in case of failure */
964 char source_str
[100];
965 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
966 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
967 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
968 __FILE__
, __PRETTY_FUNCTION__
,
969 source_str
, group_str
);
973 if (PIM_DEBUG_MROUTE
) {
975 char source_str
[100];
976 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
977 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
978 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
979 __FILE__
, __PRETTY_FUNCTION__
,
980 source_str
, group_str
,
981 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
987 void igmp_source_forward_start(struct igmp_source
*source
)
989 struct igmp_group
*group
;
993 memset (&sg
, 0, sizeof (struct prefix_sg
));
994 sg
.src
= source
->source_addr
;
995 sg
.grp
= source
->source_group
->group_addr
;
997 if (PIM_DEBUG_IGMP_TRACE
) {
998 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
1000 pim_str_sg_dump (&sg
),
1001 source
->source_group
->group_igmp_sock
->fd
,
1002 source
->source_group
->group_igmp_sock
->interface
->name
,
1003 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1006 /* Prevent IGMP interface from installing multicast route multiple
1008 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1012 group
= source
->source_group
;
1014 if (!source
->source_channel_oil
) {
1015 struct in_addr vif_source
;
1016 struct pim_interface
*pim_oif
;
1018 if (!pim_rp_set_upstream_addr (&vif_source
, source
->source_addr
, sg
.grp
))
1021 int input_iface_vif_index
= fib_lookup_if_vif_index(vif_source
);
1022 if (input_iface_vif_index
< 1) {
1023 char source_str
[100];
1024 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1025 zlog_warn("%s %s: could not find input interface for source %s",
1026 __FILE__
, __PRETTY_FUNCTION__
,
1032 Protect IGMP against adding looped MFC entries created by both
1033 source and receiver attached to the same interface. See TODO
1036 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
1038 zlog_warn("%s: multicast not enabled on oif=%s ?",
1039 __PRETTY_FUNCTION__
,
1040 source
->source_group
->group_igmp_sock
->interface
->name
);
1043 if (pim_oif
->mroute_vif_index
< 1) {
1044 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1045 __FILE__
, __PRETTY_FUNCTION__
,
1046 source
->source_group
->group_igmp_sock
->interface
->name
,
1047 pim_oif
->mroute_vif_index
);
1050 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
1051 /* ignore request for looped MFC entry */
1052 if (PIM_DEBUG_IGMP_TRACE
) {
1053 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
1054 __PRETTY_FUNCTION__
,
1055 pim_str_sg_dump (&sg
),
1056 source
->source_group
->group_igmp_sock
->fd
,
1057 source
->source_group
->group_igmp_sock
->interface
->name
,
1058 input_iface_vif_index
);
1063 source
->source_channel_oil
= pim_channel_oil_add(&sg
,
1064 input_iface_vif_index
);
1065 if (!source
->source_channel_oil
) {
1066 zlog_warn("%s %s: could not create OIL for channel (S,G)=%s",
1067 __FILE__
, __PRETTY_FUNCTION__
,
1068 pim_str_sg_dump (&sg
));
1073 result
= pim_channel_add_oif(source
->source_channel_oil
,
1074 group
->group_igmp_sock
->interface
,
1075 PIM_OIF_FLAG_PROTO_IGMP
);
1077 zlog_warn("%s: add_oif() failed with return=%d",
1083 Feed IGMPv3-gathered local membership information into PIM
1084 per-interface (S,G) state.
1086 pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
, &sg
);
1088 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1092 igmp_source_forward_stop: stop fowarding, but keep the source
1093 igmp_source_delete: stop fowarding, and delete the source
1095 void igmp_source_forward_stop(struct igmp_source
*source
)
1097 struct igmp_group
*group
;
1098 struct prefix_sg sg
;
1101 memset (&sg
, 0, sizeof (struct prefix_sg
));
1102 sg
.src
= source
->source_addr
;
1103 sg
.grp
= source
->source_group
->group_addr
;
1105 if (PIM_DEBUG_IGMP_TRACE
) {
1106 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
1107 __PRETTY_FUNCTION__
,
1108 pim_str_sg_dump (&sg
),
1109 source
->source_group
->group_igmp_sock
->fd
,
1110 source
->source_group
->group_igmp_sock
->interface
->name
,
1111 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1114 /* Prevent IGMP interface from removing multicast route multiple
1116 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1120 group
= source
->source_group
;
1123 It appears that in certain circumstances that
1124 igmp_source_forward_stop is called when IGMP forwarding
1125 was not enabled in oif_flags for this outgoing interface.
1126 Possibly because of multiple calls. When that happens, we
1127 enter the below if statement and this function returns early
1128 which in turn triggers the calling function to assert.
1129 Making the call to del_oif and ignoring the return code
1130 fixes the issue without ill effect, similar to
1131 pim_forward_stop below.
1133 result
= del_oif(source
->source_channel_oil
,
1134 group
->group_igmp_sock
->interface
,
1135 PIM_OIF_FLAG_PROTO_IGMP
);
1137 zlog_warn("%s: del_oif() failed with return=%d",
1143 Feed IGMPv3-gathered local membership information into PIM
1144 per-interface (S,G) state.
1146 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1149 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1152 void pim_forward_start(struct pim_ifchannel
*ch
)
1154 struct pim_upstream
*up
= ch
->upstream
;
1156 if (PIM_DEBUG_PIM_TRACE
) {
1157 char source_str
[100];
1158 char group_str
[100];
1159 char upstream_str
[100];
1161 pim_inet4_dump("<source?>", ch
->sg
.src
, source_str
, sizeof(source_str
));
1162 pim_inet4_dump("<group?>", ch
->sg
.grp
, group_str
, sizeof(group_str
));
1163 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
, sizeof(upstream_str
));
1164 zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
1165 __PRETTY_FUNCTION__
,
1166 source_str
, group_str
, ch
->interface
->name
, upstream_str
);
1169 if (!up
->channel_oil
) {
1170 int input_iface_vif_index
= fib_lookup_if_vif_index(up
->upstream_addr
);
1171 if (input_iface_vif_index
< 1) {
1172 char source_str
[100];
1173 pim_inet4_dump("<source?>", up
->sg
.src
, source_str
, sizeof(source_str
));
1174 zlog_warn("%s %s: could not find input interface for source %s",
1175 __FILE__
, __PRETTY_FUNCTION__
,
1180 up
->channel_oil
= pim_channel_oil_add(&up
->sg
,
1181 input_iface_vif_index
);
1182 if (!up
->channel_oil
) {
1183 zlog_warn("%s %s: could not create OIL for channel (S,G)=%s",
1184 __FILE__
, __PRETTY_FUNCTION__
,
1185 pim_str_sg_dump (&up
->sg
));
1190 pim_channel_add_oif(up
->channel_oil
,
1192 PIM_OIF_FLAG_PROTO_PIM
);
1195 void pim_forward_stop(struct pim_ifchannel
*ch
)
1197 struct pim_upstream
*up
= ch
->upstream
;
1199 if (PIM_DEBUG_PIM_TRACE
) {
1200 zlog_debug("%s: (S,G)=%s oif=%s",
1201 __PRETTY_FUNCTION__
,
1202 pim_str_sg_dump (&ch
->sg
), ch
->interface
->name
);
1205 if (!up
->channel_oil
) {
1206 zlog_warn("%s: (S,G)=%s oif=%s missing channel OIL",
1207 __PRETTY_FUNCTION__
,
1208 pim_str_sg_dump(&ch
->sg
), ch
->interface
->name
);
1213 del_oif(up
->channel_oil
,
1215 PIM_OIF_FLAG_PROTO_PIM
);