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
)) {
177 pim_ifchannel_delete_all(ifp
);
179 pim_if_addr_del_all() suffices for shutting down IGMP,
180 but not for shutting down PIM
182 pim_if_addr_del_all(ifp
);
185 pim_sock_delete() closes the socket, stops read and timer threads,
186 and kills all neighbors.
189 pim_sock_delete(ifp
, "link down");
199 #ifdef PIM_DEBUG_IFADDR_DUMP
200 static void dump_if_address(struct interface
*ifp
)
202 struct connected
*ifc
;
203 struct listnode
*node
;
205 zlog_debug("%s %s: interface %s addresses:",
206 __FILE__
, __PRETTY_FUNCTION__
,
209 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
210 struct prefix
*p
= ifc
->address
;
212 if (p
->family
!= AF_INET
)
215 zlog_debug("%s %s: interface %s address %s %s",
216 __FILE__
, __PRETTY_FUNCTION__
,
218 inet_ntoa(p
->u
.prefix4
),
219 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
220 "secondary" : "primary");
225 static int pim_zebra_if_address_add(int command
, struct zclient
*zclient
,
226 zebra_size_t length
, vrf_id_t vrf_id
)
230 struct pim_interface
*pim_ifp
;
233 zebra api notifies address adds/dels events by using the same call
234 interface_add_read below, see comments in lib/zclient.c
236 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
237 will add address to interface list by calling
238 connected_add_by_prefix()
240 c
= zebra_interface_address_read(command
, zclient
->ibuf
, vrf_id
);
244 pim_ifp
= c
->ifp
->info
;
247 if (PIM_DEBUG_ZEBRA
) {
249 prefix2str(p
, buf
, BUFSIZ
);
250 zlog_debug("%s: %s connected IP address %s flags %u %s",
252 c
->ifp
->name
, buf
, c
->flags
,
253 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
255 #ifdef PIM_DEBUG_IFADDR_DUMP
256 dump_if_address(c
->ifp
);
260 if (p
->family
!= AF_INET
)
262 struct listnode
*cnode
;
263 struct connected
*conn
;
266 for (ALL_LIST_ELEMENTS_RO (c
->ifp
->connected
, cnode
, conn
))
268 if (conn
->address
->family
== AF_INET
)
271 if (!v4addrs
&& pim_ifp
)
273 pim_ifp
->primary_address
= pim_find_primary_addr (c
->ifp
);
274 pim_if_addr_add_all (c
->ifp
);
275 pim_if_add_vif (c
->ifp
);
280 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
281 /* trying to add primary address */
283 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
284 if (primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
285 if (PIM_DEBUG_ZEBRA
) {
286 /* but we had a primary address already */
290 prefix2str(p
, buf
, BUFSIZ
);
292 zlog_warn("%s: %s : forcing secondary flag on %s",
296 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
302 pim_rp_check_on_if_add(pim_ifp
);
304 if (if_is_loopback (c
->ifp
))
306 struct listnode
*ifnode
;
307 struct interface
*ifp
;
309 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
))
311 if (!if_is_loopback (ifp
) && if_is_operative (ifp
))
312 pim_if_addr_add_all (ifp
);
319 static int pim_zebra_if_address_del(int command
, struct zclient
*client
,
320 zebra_size_t length
, vrf_id_t vrf_id
)
326 zebra api notifies address adds/dels events by using the same call
327 interface_add_read below, see comments in lib/zclient.c
329 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
330 will remove address from interface list by calling
331 connected_delete_by_prefix()
333 c
= zebra_interface_address_read(command
, client
->ibuf
, vrf_id
);
338 if (p
->family
!= AF_INET
)
341 if (PIM_DEBUG_ZEBRA
) {
343 prefix2str(p
, buf
, BUFSIZ
);
344 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
346 c
->ifp
->name
, buf
, c
->flags
,
347 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
349 #ifdef PIM_DEBUG_IFADDR_DUMP
350 dump_if_address(c
->ifp
);
354 pim_if_addr_del(c
, 0);
356 pim_i_am_rp_re_evaluate();
361 static void scan_upstream_rpf_cache()
363 struct listnode
*up_node
;
364 struct listnode
*up_nextnode
;
365 struct pim_upstream
*up
;
367 for (ALL_LIST_ELEMENTS(pim_upstream_list
, up_node
, up_nextnode
, up
)) {
368 struct in_addr old_rpf_addr
;
369 struct interface
*old_interface
;
370 enum pim_rpf_result rpf_result
;
372 old_interface
= up
->rpf
.source_nexthop
.interface
;
373 rpf_result
= pim_rpf_update(up
, &old_rpf_addr
);
374 if (rpf_result
== PIM_RPF_FAILURE
)
377 if (rpf_result
== PIM_RPF_CHANGED
) {
380 * We have detected a case where we might need to rescan
381 * the inherited o_list so do it.
383 if (up
->channel_oil
->oil_inherited_rescan
)
385 pim_upstream_inherited_olist_decide (up
);
386 up
->channel_oil
->oil_inherited_rescan
= 0;
389 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
391 * If we come up real fast we can be here
392 * where the mroute has not been installed
395 if (!up
->channel_oil
->installed
)
396 pim_mroute_add (up
->channel_oil
, __PRETTY_FUNCTION__
);
399 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
401 Transitions from Joined State
403 RPF'(S,G) changes not due to an Assert
405 The upstream (S,G) state machine remains in Joined
406 state. Send Join(S,G) to the new upstream neighbor, which is
407 the new value of RPF'(S,G). Send Prune(S,G) to the old
408 upstream neighbor, which is the old value of RPF'(S,G). Set
409 the Join Timer (JT) to expire after t_periodic seconds.
413 /* send Prune(S,G) to the old upstream neighbor */
414 pim_joinprune_send(old_interface
, old_rpf_addr
,
417 /* send Join(S,G) to the current upstream neighbor */
418 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
419 up
->rpf
.rpf_addr
.u
.prefix4
,
423 pim_upstream_join_timer_restart(up
);
424 } /* up->join_state == PIM_UPSTREAM_JOINED */
426 /* FIXME can join_desired actually be changed by pim_rpf_update()
427 returning PIM_RPF_CHANGED ? */
428 pim_upstream_update_join_desired(up
);
430 } /* PIM_RPF_CHANGED */
432 } /* for (qpim_upstream_list) */
437 pim_scan_individual_oil (struct channel_oil
*c_oil
)
439 struct in_addr vif_source
;
440 int input_iface_vif_index
;
443 if (!pim_rp_set_upstream_addr (&vif_source
, c_oil
->oil
.mfcc_origin
, c_oil
->oil
.mfcc_mcastgrp
))
446 input_iface_vif_index
= fib_lookup_if_vif_index (vif_source
);
447 if (input_iface_vif_index
< 1)
451 char source_str
[INET_ADDRSTRLEN
];
452 char group_str
[INET_ADDRSTRLEN
];
453 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
454 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
455 zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
456 __FILE__
, __PRETTY_FUNCTION__
, c_oil
->oil
.mfcc_parent
,
457 source_str
, group_str
);
459 pim_mroute_del (c_oil
, __PRETTY_FUNCTION__
);
463 if (input_iface_vif_index
== c_oil
->oil
.mfcc_parent
)
465 if (!c_oil
->installed
)
466 pim_mroute_add (c_oil
, __PRETTY_FUNCTION__
);
474 struct interface
*old_iif
= pim_if_find_by_vif_index(c_oil
->oil
.mfcc_parent
);
475 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
476 char source_str
[INET_ADDRSTRLEN
];
477 char group_str
[INET_ADDRSTRLEN
];
478 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
479 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
480 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
481 __FILE__
, __PRETTY_FUNCTION__
,
482 source_str
, group_str
,
483 old_iif
->name
, c_oil
->oil
.mfcc_parent
,
484 new_iif
->name
, input_iface_vif_index
);
487 /* new iif loops to existing oif ? */
488 if (c_oil
->oil
.mfcc_ttls
[input_iface_vif_index
])
490 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
492 if (PIM_DEBUG_ZEBRA
) {
493 char source_str
[INET_ADDRSTRLEN
];
494 char group_str
[INET_ADDRSTRLEN
];
495 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
496 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
497 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
498 __FILE__
, __PRETTY_FUNCTION__
,
499 source_str
, group_str
,
500 new_iif
->name
, input_iface_vif_index
);
503 //del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
506 /* update iif vif_index */
507 old_vif_index
= c_oil
->oil
.mfcc_parent
;
508 c_oil
->oil
.mfcc_parent
= input_iface_vif_index
;
510 /* update kernel multicast forwarding cache (MFC) */
511 if (pim_mroute_add(c_oil
, __PRETTY_FUNCTION__
))
513 if (PIM_DEBUG_MROUTE
)
515 /* just log warning */
516 struct interface
*old_iif
= pim_if_find_by_vif_index(old_vif_index
);
517 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
518 char source_str
[INET_ADDRSTRLEN
];
519 char group_str
[INET_ADDRSTRLEN
];
520 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
521 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
522 zlog_debug("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
523 __FILE__
, __PRETTY_FUNCTION__
,
524 source_str
, group_str
,
525 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
526 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
533 struct listnode
*node
;
534 struct listnode
*nextnode
;
535 struct channel_oil
*c_oil
;
537 qpim_scan_oil_last
= pim_time_monotonic_sec();
538 ++qpim_scan_oil_events
;
540 for (ALL_LIST_ELEMENTS(pim_channel_oil_list
, node
, nextnode
, c_oil
))
541 pim_scan_individual_oil (c_oil
);
544 static int on_rpf_cache_refresh(struct thread
*t
)
546 zassert(qpim_rpf_cache_refresher
);
548 qpim_rpf_cache_refresher
= 0;
550 /* update PIM protocol state */
551 scan_upstream_rpf_cache();
553 /* update kernel multicast forwarding cache (MFC) */
556 qpim_rpf_cache_refresh_last
= pim_time_monotonic_sec();
557 ++qpim_rpf_cache_refresh_events
;
563 void sched_rpf_cache_refresh(void)
565 ++qpim_rpf_cache_refresh_requests
;
567 pim_rpf_set_refresh_time ();
569 if (qpim_rpf_cache_refresher
) {
570 /* Refresh timer is already running */
574 /* Start refresh timer */
576 if (PIM_DEBUG_ZEBRA
) {
577 zlog_debug("%s: triggering %ld msec timer",
579 qpim_rpf_cache_refresh_delay_msec
);
582 THREAD_TIMER_MSEC_ON(master
, qpim_rpf_cache_refresher
,
583 on_rpf_cache_refresh
,
584 0, qpim_rpf_cache_refresh_delay_msec
);
587 static int redist_read_ipv4_route(int command
, struct zclient
*zclient
,
588 zebra_size_t length
, vrf_id_t vrf_id
)
591 struct zapi_ipv4 api
;
593 struct in_addr nexthop
;
594 struct prefix_ipv4 p
;
597 if (length
< min_len
) {
598 zlog_warn("%s %s: short buffer: length=%d min=%d",
599 __FILE__
, __PRETTY_FUNCTION__
,
608 /* Type, flags, message. */
609 api
.type
= stream_getc(s
);
610 api
.instance
= stream_getw (s
);
611 api
.flags
= stream_getl(s
);
612 api
.message
= stream_getc(s
);
614 /* IPv4 prefix length. */
615 memset(&p
, 0, sizeof(struct prefix_ipv4
));
617 p
.prefixlen
= stream_getc(s
);
621 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? 5 : 0 +
622 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? 5 : 0 +
623 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? 1 : 0 +
624 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? 4 : 0;
626 if (PIM_DEBUG_ZEBRA
) {
627 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
628 __FILE__
, __PRETTY_FUNCTION__
,
630 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
631 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
632 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
633 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
637 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
639 /* Nexthop, ifindex, distance, metric. */
640 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
641 api
.nexthop_num
= stream_getc(s
);
642 nexthop
.s_addr
= stream_get_ipv4(s
);
644 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
)) {
645 api
.ifindex_num
= stream_getc(s
);
646 ifindex
= stream_getl(s
);
649 api
.distance
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ?
653 api
.metric
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ?
657 if (CHECK_FLAG (api
.message
, ZAPI_MESSAGE_TAG
))
658 api
.tag
= stream_getl (s
);
663 case ZEBRA_REDISTRIBUTE_IPV4_ADD
:
664 if (PIM_DEBUG_ZEBRA
) {
665 char buf
[2][INET_ADDRSTRLEN
];
666 zlog_debug("%s: add %s %s/%d "
667 "nexthop %s ifindex %d metric%s %u distance%s %u",
669 zebra_route_string(api
.type
),
670 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
672 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
674 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
676 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
680 case ZEBRA_REDISTRIBUTE_IPV4_DEL
:
681 if (PIM_DEBUG_ZEBRA
) {
682 char buf
[2][INET_ADDRSTRLEN
];
683 zlog_debug("%s: delete %s %s/%d "
684 "nexthop %s ifindex %d metric%s %u distance%s %u",
686 zebra_route_string(api
.type
),
687 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
689 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
691 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
693 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
698 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__
, command
);
702 sched_rpf_cache_refresh();
709 pim_zebra_connected (struct zclient
*zclient
)
711 zclient_send_reg_requests (zclient
, VRF_DEFAULT
);
714 void pim_zebra_init(char *zebra_sock_path
)
719 zclient_serv_path_set(zebra_sock_path
);
721 #ifdef HAVE_TCP_ZEBRA
722 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT
);
724 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
727 /* Socket for receiving updates from Zebra daemon */
728 qpim_zclient_update
= zclient_new (master
);
730 qpim_zclient_update
->zebra_connected
= pim_zebra_connected
;
731 qpim_zclient_update
->router_id_update
= pim_router_id_update_zebra
;
732 qpim_zclient_update
->interface_add
= pim_zebra_if_add
;
733 qpim_zclient_update
->interface_delete
= pim_zebra_if_del
;
734 qpim_zclient_update
->interface_up
= pim_zebra_if_state_up
;
735 qpim_zclient_update
->interface_down
= pim_zebra_if_state_down
;
736 qpim_zclient_update
->interface_address_add
= pim_zebra_if_address_add
;
737 qpim_zclient_update
->interface_address_delete
= pim_zebra_if_address_del
;
738 qpim_zclient_update
->redistribute_route_ipv4_add
= redist_read_ipv4_route
;
739 qpim_zclient_update
->redistribute_route_ipv4_del
= redist_read_ipv4_route
;
741 zclient_init(qpim_zclient_update
, ZEBRA_ROUTE_PIM
, 0);
742 if (PIM_DEBUG_PIM_TRACE
) {
743 zlog_info("zclient_init cleared redistribution request");
746 zassert(qpim_zclient_update
->redist_default
== ZEBRA_ROUTE_PIM
);
748 /* Request all redistribution */
749 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
750 if (i
== qpim_zclient_update
->redist_default
)
752 vrf_bitmap_set (qpim_zclient_update
->redist
[AFI_IP
][i
], VRF_DEFAULT
);;
753 if (PIM_DEBUG_PIM_TRACE
) {
754 zlog_debug("%s: requesting redistribution for %s (%i)",
755 __PRETTY_FUNCTION__
, zebra_route_string(i
), i
);
759 /* Request default information */
760 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
761 qpim_zclient_update
, VRF_DEFAULT
);
763 if (PIM_DEBUG_PIM_TRACE
) {
764 zlog_info("%s: requesting default information redistribution",
765 __PRETTY_FUNCTION__
);
767 zlog_notice("%s: zclient update socket initialized",
768 __PRETTY_FUNCTION__
);
771 zclient_lookup_new();
774 void igmp_anysource_forward_start(struct igmp_group
*group
)
776 struct igmp_source
*source
;
777 struct in_addr src_addr
= { .s_addr
= 0 };
778 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
779 zassert(group
->group_filtermode_isexcl
);
780 zassert(listcount(group
->group_source_list
) < 1);
782 source
= source_new (group
, src_addr
);
785 zlog_warn ("%s: Failure to create * source", __PRETTY_FUNCTION__
);
789 igmp_source_forward_start (source
);
792 void igmp_anysource_forward_stop(struct igmp_group
*group
)
794 struct igmp_source
*source
;
795 struct in_addr star
= { .s_addr
= 0 };
797 source
= igmp_find_source_by_addr (group
, star
);
799 igmp_source_forward_stop (source
);
802 static int fib_lookup_if_vif_index(struct in_addr addr
)
804 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
807 ifindex_t first_ifindex
;
809 num_ifindex
= zclient_lookup_nexthop(nexthop_tab
,
811 PIM_NEXTHOP_LOOKUP_MAX
);
812 if (num_ifindex
< 1) {
815 char addr_str
[INET_ADDRSTRLEN
];
816 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
817 zlog_debug("%s %s: could not find nexthop ifindex for address %s",
818 __FILE__
, __PRETTY_FUNCTION__
,
824 first_ifindex
= nexthop_tab
[0].ifindex
;
826 if (num_ifindex
> 1) {
829 char addr_str
[INET_ADDRSTRLEN
];
830 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
831 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
832 __FILE__
, __PRETTY_FUNCTION__
,
833 num_ifindex
, addr_str
, first_ifindex
);
835 /* debug warning only, do not return */
838 if (PIM_DEBUG_ZEBRA
) {
839 char addr_str
[INET_ADDRSTRLEN
];
840 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
841 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
842 __FILE__
, __PRETTY_FUNCTION__
,
843 first_ifindex
, ifindex2ifname(first_ifindex
), addr_str
);
846 vif_index
= pim_if_find_vifindex_by_ifindex(first_ifindex
);
851 char addr_str
[INET_ADDRSTRLEN
];
852 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
853 zlog_debug("%s %s: low vif_index=%d < 1 nexthop for address %s",
854 __FILE__
, __PRETTY_FUNCTION__
,
855 vif_index
, addr_str
);
863 static int del_oif(struct channel_oil
*channel_oil
,
864 struct interface
*oif
,
867 struct pim_interface
*pim_ifp
;
872 if (PIM_DEBUG_MROUTE
) {
873 char group_str
[INET_ADDRSTRLEN
];
874 char source_str
[INET_ADDRSTRLEN
];
875 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
876 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
877 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
878 __FILE__
, __PRETTY_FUNCTION__
,
879 source_str
, group_str
,
880 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
883 /* Prevent single protocol from unsubscribing same interface from
884 channel (S,G) multiple times */
885 if (!(channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & proto_mask
)) {
886 if (PIM_DEBUG_MROUTE
)
888 char group_str
[INET_ADDRSTRLEN
];
889 char source_str
[INET_ADDRSTRLEN
];
890 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
891 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
892 zlog_debug("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
893 __FILE__
, __PRETTY_FUNCTION__
,
894 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
895 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
896 source_str
, group_str
);
901 /* Mark that protocol is no longer interested in this OIF */
902 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] &= ~proto_mask
;
904 /* Allow multiple protocols to unsubscribe same interface from
905 channel (S,G) multiple times, by silently ignoring requests while
906 there is at least one protocol interested in the channel */
907 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
909 /* Check the OIF keeps existing before returning, and only log
911 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
912 if (PIM_DEBUG_MROUTE
)
914 char group_str
[INET_ADDRSTRLEN
];
915 char source_str
[INET_ADDRSTRLEN
];
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_debug("%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
);
929 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
932 if (PIM_DEBUG_MROUTE
)
934 char group_str
[INET_ADDRSTRLEN
];
935 char source_str
[INET_ADDRSTRLEN
];
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_debug("%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
);
946 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = 0;
948 if (pim_mroute_add(channel_oil
, __PRETTY_FUNCTION__
)) {
949 char group_str
[INET_ADDRSTRLEN
];
950 char source_str
[INET_ADDRSTRLEN
];
951 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
952 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
953 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
954 __FILE__
, __PRETTY_FUNCTION__
,
955 oif
->name
, pim_ifp
->mroute_vif_index
,
956 source_str
, group_str
);
958 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
962 --channel_oil
->oil_size
;
964 if (channel_oil
->oil_size
< 1) {
965 if (pim_mroute_del(channel_oil
, __PRETTY_FUNCTION__
)) {
966 if (PIM_DEBUG_MROUTE
)
968 /* just log a warning in case of failure */
969 char group_str
[INET_ADDRSTRLEN
];
970 char source_str
[INET_ADDRSTRLEN
];
971 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
972 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
973 zlog_debug("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
974 __FILE__
, __PRETTY_FUNCTION__
,
975 source_str
, group_str
);
980 if (PIM_DEBUG_MROUTE
) {
981 char group_str
[INET_ADDRSTRLEN
];
982 char source_str
[INET_ADDRSTRLEN
];
983 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
984 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
985 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
986 __FILE__
, __PRETTY_FUNCTION__
,
987 source_str
, group_str
,
988 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
994 void igmp_source_forward_start(struct igmp_source
*source
)
996 struct igmp_group
*group
;
1000 memset (&sg
, 0, sizeof (struct prefix_sg
));
1001 sg
.src
= source
->source_addr
;
1002 sg
.grp
= source
->source_group
->group_addr
;
1004 if (PIM_DEBUG_IGMP_TRACE
) {
1005 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
1006 __PRETTY_FUNCTION__
,
1007 pim_str_sg_dump (&sg
),
1008 source
->source_group
->group_igmp_sock
->fd
,
1009 source
->source_group
->group_igmp_sock
->interface
->name
,
1010 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1013 /* Prevent IGMP interface from installing multicast route multiple
1015 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1019 group
= source
->source_group
;
1021 if (!source
->source_channel_oil
) {
1022 struct in_addr vif_source
;
1023 struct pim_interface
*pim_oif
;
1025 if (!pim_rp_set_upstream_addr (&vif_source
, source
->source_addr
, sg
.grp
))
1028 int input_iface_vif_index
= fib_lookup_if_vif_index(vif_source
);
1029 if (input_iface_vif_index
< 1) {
1030 if (PIM_DEBUG_IGMP_TRACE
)
1032 char source_str
[INET_ADDRSTRLEN
];
1033 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1034 zlog_debug("%s %s: could not find input interface for source %s",
1035 __FILE__
, __PRETTY_FUNCTION__
,
1042 Protect IGMP against adding looped MFC entries created by both
1043 source and receiver attached to the same interface. See TODO
1046 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
1048 if (PIM_DEBUG_IGMP_TRACE
)
1050 zlog_debug("%s: multicast not enabled on oif=%s ?",
1051 __PRETTY_FUNCTION__
,
1052 source
->source_group
->group_igmp_sock
->interface
->name
);
1057 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
1058 /* ignore request for looped MFC entry */
1059 if (PIM_DEBUG_IGMP_TRACE
) {
1060 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
1061 __PRETTY_FUNCTION__
,
1062 pim_str_sg_dump (&sg
),
1063 source
->source_group
->group_igmp_sock
->fd
,
1064 source
->source_group
->group_igmp_sock
->interface
->name
,
1065 input_iface_vif_index
);
1070 source
->source_channel_oil
= pim_channel_oil_add(&sg
,
1071 input_iface_vif_index
);
1072 if (!source
->source_channel_oil
) {
1073 if (PIM_DEBUG_IGMP_TRACE
)
1075 zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
1076 __FILE__
, __PRETTY_FUNCTION__
,
1077 pim_str_sg_dump (&sg
));
1083 result
= pim_channel_add_oif(source
->source_channel_oil
,
1084 group
->group_igmp_sock
->interface
,
1085 PIM_OIF_FLAG_PROTO_IGMP
);
1087 if (PIM_DEBUG_MROUTE
)
1089 zlog_warn("%s: add_oif() failed with return=%d",
1096 Feed IGMPv3-gathered local membership information into PIM
1097 per-interface (S,G) state.
1099 pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
, &sg
);
1101 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1105 igmp_source_forward_stop: stop fowarding, but keep the source
1106 igmp_source_delete: stop fowarding, and delete the source
1108 void igmp_source_forward_stop(struct igmp_source
*source
)
1110 struct igmp_group
*group
;
1111 struct prefix_sg sg
;
1114 memset (&sg
, 0, sizeof (struct prefix_sg
));
1115 sg
.src
= source
->source_addr
;
1116 sg
.grp
= source
->source_group
->group_addr
;
1118 if (PIM_DEBUG_IGMP_TRACE
) {
1119 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
1120 __PRETTY_FUNCTION__
,
1121 pim_str_sg_dump (&sg
),
1122 source
->source_group
->group_igmp_sock
->fd
,
1123 source
->source_group
->group_igmp_sock
->interface
->name
,
1124 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1127 /* Prevent IGMP interface from removing multicast route multiple
1129 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1133 group
= source
->source_group
;
1136 It appears that in certain circumstances that
1137 igmp_source_forward_stop is called when IGMP forwarding
1138 was not enabled in oif_flags for this outgoing interface.
1139 Possibly because of multiple calls. When that happens, we
1140 enter the below if statement and this function returns early
1141 which in turn triggers the calling function to assert.
1142 Making the call to del_oif and ignoring the return code
1143 fixes the issue without ill effect, similar to
1144 pim_forward_stop below.
1146 result
= del_oif(source
->source_channel_oil
,
1147 group
->group_igmp_sock
->interface
,
1148 PIM_OIF_FLAG_PROTO_IGMP
);
1150 if (PIM_DEBUG_IGMP_TRACE
)
1151 zlog_debug("%s: del_oif() failed with return=%d",
1157 Feed IGMPv3-gathered local membership information into PIM
1158 per-interface (S,G) state.
1160 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1163 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1166 void pim_forward_start(struct pim_ifchannel
*ch
)
1168 struct pim_upstream
*up
= ch
->upstream
;
1170 if (PIM_DEBUG_PIM_TRACE
) {
1171 char source_str
[INET_ADDRSTRLEN
];
1172 char group_str
[INET_ADDRSTRLEN
];
1173 char upstream_str
[INET_ADDRSTRLEN
];
1175 pim_inet4_dump("<source?>", ch
->sg
.src
, source_str
, sizeof(source_str
));
1176 pim_inet4_dump("<group?>", ch
->sg
.grp
, group_str
, sizeof(group_str
));
1177 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
, sizeof(upstream_str
));
1178 zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
1179 __PRETTY_FUNCTION__
,
1180 source_str
, group_str
, ch
->interface
->name
, upstream_str
);
1183 if (!up
->channel_oil
) {
1184 int input_iface_vif_index
= fib_lookup_if_vif_index(up
->upstream_addr
);
1185 if (input_iface_vif_index
< 1) {
1186 if (PIM_DEBUG_PIM_TRACE
)
1188 char source_str
[INET_ADDRSTRLEN
];
1189 pim_inet4_dump("<source?>", up
->sg
.src
, source_str
, sizeof(source_str
));
1190 zlog_debug("%s %s: could not find input interface for source %s",
1191 __FILE__
, __PRETTY_FUNCTION__
,
1197 up
->channel_oil
= pim_channel_oil_add(&up
->sg
,
1198 input_iface_vif_index
);
1199 if (!up
->channel_oil
) {
1200 if (PIM_DEBUG_PIM_TRACE
)
1201 zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
1202 __FILE__
, __PRETTY_FUNCTION__
,
1208 pim_channel_add_oif(up
->channel_oil
,
1210 PIM_OIF_FLAG_PROTO_PIM
);
1213 void pim_forward_stop(struct pim_ifchannel
*ch
)
1215 struct pim_upstream
*up
= ch
->upstream
;
1217 if (PIM_DEBUG_PIM_TRACE
) {
1218 zlog_debug("%s: (S,G)=%s oif=%s",
1219 __PRETTY_FUNCTION__
,
1220 ch
->sg_str
, ch
->interface
->name
);
1223 if (!up
->channel_oil
) {
1224 if (PIM_DEBUG_PIM_TRACE
)
1225 zlog_debug("%s: (S,G)=%s oif=%s missing channel OIL",
1226 __PRETTY_FUNCTION__
,
1227 ch
->sg_str
, ch
->interface
->name
);
1232 del_oif(up
->channel_oil
,
1234 PIM_OIF_FLAG_PROTO_PIM
);