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(pim_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(pim_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
)) {
891 if (PIM_DEBUG_MROUTE
)
894 char source_str
[100];
895 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
896 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
897 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
898 __FILE__
, __PRETTY_FUNCTION__
,
899 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
900 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
901 source_str
, group_str
);
906 /* Mark that protocol is no longer interested in this OIF */
907 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] &= ~proto_mask
;
909 /* Allow multiple protocols to unsubscribe same interface from
910 channel (S,G) multiple times, by silently ignoring requests while
911 there is at least one protocol interested in the channel */
912 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
914 /* Check the OIF keeps existing before returning, and only log
916 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
918 char source_str
[100];
919 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
920 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
921 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
922 __FILE__
, __PRETTY_FUNCTION__
,
923 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
924 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
925 source_str
, group_str
);
931 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
935 char source_str
[100];
936 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
937 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
938 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
939 __FILE__
, __PRETTY_FUNCTION__
,
940 oif
->name
, pim_ifp
->mroute_vif_index
,
941 source_str
, group_str
);
945 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = 0;
947 if (pim_mroute_add(channel_oil
)) {
949 char source_str
[100];
950 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
951 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
952 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
953 __FILE__
, __PRETTY_FUNCTION__
,
954 oif
->name
, pim_ifp
->mroute_vif_index
,
955 source_str
, group_str
);
957 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
961 --channel_oil
->oil_size
;
963 if (channel_oil
->oil_size
< 1) {
964 if (pim_mroute_del(channel_oil
)) {
965 /* just log a warning in case of failure */
967 char source_str
[100];
968 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
969 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
970 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
971 __FILE__
, __PRETTY_FUNCTION__
,
972 source_str
, group_str
);
976 if (PIM_DEBUG_MROUTE
) {
978 char source_str
[100];
979 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
980 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
981 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
982 __FILE__
, __PRETTY_FUNCTION__
,
983 source_str
, group_str
,
984 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
990 void igmp_source_forward_start(struct igmp_source
*source
)
992 struct igmp_group
*group
;
996 memset (&sg
, 0, sizeof (struct prefix_sg
));
997 sg
.src
= source
->source_addr
;
998 sg
.grp
= source
->source_group
->group_addr
;
1000 if (PIM_DEBUG_IGMP_TRACE
) {
1001 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
1002 __PRETTY_FUNCTION__
,
1003 pim_str_sg_dump (&sg
),
1004 source
->source_group
->group_igmp_sock
->fd
,
1005 source
->source_group
->group_igmp_sock
->interface
->name
,
1006 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1009 /* Prevent IGMP interface from installing multicast route multiple
1011 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1015 group
= source
->source_group
;
1017 if (!source
->source_channel_oil
) {
1018 struct in_addr vif_source
;
1019 struct pim_interface
*pim_oif
;
1021 if (!pim_rp_set_upstream_addr (&vif_source
, source
->source_addr
, sg
.grp
))
1024 int input_iface_vif_index
= fib_lookup_if_vif_index(vif_source
);
1025 if (input_iface_vif_index
< 1) {
1026 char source_str
[100];
1027 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1028 zlog_warn("%s %s: could not find input interface for source %s",
1029 __FILE__
, __PRETTY_FUNCTION__
,
1035 Protect IGMP against adding looped MFC entries created by both
1036 source and receiver attached to the same interface. See TODO
1039 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
1041 zlog_warn("%s: multicast not enabled on oif=%s ?",
1042 __PRETTY_FUNCTION__
,
1043 source
->source_group
->group_igmp_sock
->interface
->name
);
1046 if (pim_oif
->mroute_vif_index
< 1) {
1047 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1048 __FILE__
, __PRETTY_FUNCTION__
,
1049 source
->source_group
->group_igmp_sock
->interface
->name
,
1050 pim_oif
->mroute_vif_index
);
1053 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
1054 /* ignore request for looped MFC entry */
1055 if (PIM_DEBUG_IGMP_TRACE
) {
1056 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
1057 __PRETTY_FUNCTION__
,
1058 pim_str_sg_dump (&sg
),
1059 source
->source_group
->group_igmp_sock
->fd
,
1060 source
->source_group
->group_igmp_sock
->interface
->name
,
1061 input_iface_vif_index
);
1066 source
->source_channel_oil
= pim_channel_oil_add(&sg
,
1067 input_iface_vif_index
);
1068 if (!source
->source_channel_oil
) {
1069 zlog_warn("%s %s: could not create OIL for channel (S,G)=%s",
1070 __FILE__
, __PRETTY_FUNCTION__
,
1071 pim_str_sg_dump (&sg
));
1076 result
= pim_channel_add_oif(source
->source_channel_oil
,
1077 group
->group_igmp_sock
->interface
,
1078 PIM_OIF_FLAG_PROTO_IGMP
);
1080 zlog_warn("%s: add_oif() failed with return=%d",
1086 Feed IGMPv3-gathered local membership information into PIM
1087 per-interface (S,G) state.
1089 pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
, &sg
);
1091 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1095 igmp_source_forward_stop: stop fowarding, but keep the source
1096 igmp_source_delete: stop fowarding, and delete the source
1098 void igmp_source_forward_stop(struct igmp_source
*source
)
1100 struct igmp_group
*group
;
1101 struct prefix_sg sg
;
1104 memset (&sg
, 0, sizeof (struct prefix_sg
));
1105 sg
.src
= source
->source_addr
;
1106 sg
.grp
= source
->source_group
->group_addr
;
1108 if (PIM_DEBUG_IGMP_TRACE
) {
1109 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
1110 __PRETTY_FUNCTION__
,
1111 pim_str_sg_dump (&sg
),
1112 source
->source_group
->group_igmp_sock
->fd
,
1113 source
->source_group
->group_igmp_sock
->interface
->name
,
1114 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1117 /* Prevent IGMP interface from removing multicast route multiple
1119 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1123 group
= source
->source_group
;
1126 It appears that in certain circumstances that
1127 igmp_source_forward_stop is called when IGMP forwarding
1128 was not enabled in oif_flags for this outgoing interface.
1129 Possibly because of multiple calls. When that happens, we
1130 enter the below if statement and this function returns early
1131 which in turn triggers the calling function to assert.
1132 Making the call to del_oif and ignoring the return code
1133 fixes the issue without ill effect, similar to
1134 pim_forward_stop below.
1136 result
= del_oif(source
->source_channel_oil
,
1137 group
->group_igmp_sock
->interface
,
1138 PIM_OIF_FLAG_PROTO_IGMP
);
1140 zlog_warn("%s: del_oif() failed with return=%d",
1146 Feed IGMPv3-gathered local membership information into PIM
1147 per-interface (S,G) state.
1149 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1152 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1155 void pim_forward_start(struct pim_ifchannel
*ch
)
1157 struct pim_upstream
*up
= ch
->upstream
;
1159 if (PIM_DEBUG_PIM_TRACE
) {
1160 char source_str
[100];
1161 char group_str
[100];
1162 char upstream_str
[100];
1164 pim_inet4_dump("<source?>", ch
->sg
.src
, source_str
, sizeof(source_str
));
1165 pim_inet4_dump("<group?>", ch
->sg
.grp
, group_str
, sizeof(group_str
));
1166 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
, sizeof(upstream_str
));
1167 zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
1168 __PRETTY_FUNCTION__
,
1169 source_str
, group_str
, ch
->interface
->name
, upstream_str
);
1172 if (!up
->channel_oil
) {
1173 int input_iface_vif_index
= fib_lookup_if_vif_index(up
->upstream_addr
);
1174 if (input_iface_vif_index
< 1) {
1175 char source_str
[100];
1176 pim_inet4_dump("<source?>", up
->sg
.src
, source_str
, sizeof(source_str
));
1177 zlog_warn("%s %s: could not find input interface for source %s",
1178 __FILE__
, __PRETTY_FUNCTION__
,
1183 up
->channel_oil
= pim_channel_oil_add(&up
->sg
,
1184 input_iface_vif_index
);
1185 if (!up
->channel_oil
) {
1186 zlog_warn("%s %s: could not create OIL for channel (S,G)=%s",
1187 __FILE__
, __PRETTY_FUNCTION__
,
1188 pim_str_sg_dump (&up
->sg
));
1193 pim_channel_add_oif(up
->channel_oil
,
1195 PIM_OIF_FLAG_PROTO_PIM
);
1198 void pim_forward_stop(struct pim_ifchannel
*ch
)
1200 struct pim_upstream
*up
= ch
->upstream
;
1202 if (PIM_DEBUG_PIM_TRACE
) {
1203 zlog_debug("%s: (S,G)=%s oif=%s",
1204 __PRETTY_FUNCTION__
,
1205 pim_str_sg_dump (&ch
->sg
), ch
->interface
->name
);
1208 if (!up
->channel_oil
) {
1209 zlog_warn("%s: (S,G)=%s oif=%s missing channel OIL",
1210 __PRETTY_FUNCTION__
,
1211 pim_str_sg_dump(&ch
->sg
), ch
->interface
->name
);
1216 del_oif(up
->channel_oil
,
1218 PIM_OIF_FLAG_PROTO_PIM
);