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 pim_interface
*pim_ifp
;
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
);
240 pim_ifp
= c
->ifp
->info
;
243 if (PIM_DEBUG_ZEBRA
) {
245 prefix2str(p
, buf
, BUFSIZ
);
246 zlog_debug("%s: %s connected IP address %s flags %u %s",
248 c
->ifp
->name
, buf
, c
->flags
,
249 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
251 #ifdef PIM_DEBUG_IFADDR_DUMP
252 dump_if_address(c
->ifp
);
256 if (p
->family
!= AF_INET
)
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 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
277 /* trying to add primary address */
279 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
280 if (primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
281 if (PIM_DEBUG_ZEBRA
) {
282 /* but we had a primary address already */
286 prefix2str(p
, buf
, BUFSIZ
);
288 zlog_warn("%s: %s : forcing secondary flag on %s",
292 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
298 pim_rp_check_on_if_add(pim_ifp
);
300 if (if_is_loopback (c
->ifp
))
302 struct listnode
*ifnode
;
303 struct interface
*ifp
;
305 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
))
307 if (!if_is_loopback (ifp
) && if_is_operative (ifp
))
308 pim_if_addr_add_all (ifp
);
315 static int pim_zebra_if_address_del(int command
, struct zclient
*client
,
316 zebra_size_t length
, vrf_id_t vrf_id
)
322 zebra api notifies address adds/dels events by using the same call
323 interface_add_read below, see comments in lib/zclient.c
325 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
326 will remove address from interface list by calling
327 connected_delete_by_prefix()
329 c
= zebra_interface_address_read(command
, client
->ibuf
, vrf_id
);
334 if (p
->family
!= AF_INET
)
337 if (PIM_DEBUG_ZEBRA
) {
339 prefix2str(p
, buf
, BUFSIZ
);
340 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
342 c
->ifp
->name
, buf
, c
->flags
,
343 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
345 #ifdef PIM_DEBUG_IFADDR_DUMP
346 dump_if_address(c
->ifp
);
350 pim_if_addr_del(c
, 0);
352 pim_i_am_rp_re_evaluate();
357 static void scan_upstream_rpf_cache()
359 struct listnode
*up_node
;
360 struct listnode
*up_nextnode
;
361 struct pim_upstream
*up
;
363 for (ALL_LIST_ELEMENTS(pim_upstream_list
, up_node
, up_nextnode
, up
)) {
364 struct in_addr old_rpf_addr
;
365 struct interface
*old_interface
;
366 enum pim_rpf_result rpf_result
;
368 old_interface
= up
->rpf
.source_nexthop
.interface
;
369 rpf_result
= pim_rpf_update(up
, &old_rpf_addr
);
370 if (rpf_result
== PIM_RPF_FAILURE
)
373 if (rpf_result
== PIM_RPF_CHANGED
) {
375 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
377 * If we come up real fast we can be here
378 * where the mroute has not been installed
381 if (up
->channel_oil
&& !up
->channel_oil
->installed
)
382 pim_mroute_add (up
->channel_oil
, __PRETTY_FUNCTION__
);
385 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
387 Transitions from Joined State
389 RPF'(S,G) changes not due to an Assert
391 The upstream (S,G) state machine remains in Joined
392 state. Send Join(S,G) to the new upstream neighbor, which is
393 the new value of RPF'(S,G). Send Prune(S,G) to the old
394 upstream neighbor, which is the old value of RPF'(S,G). Set
395 the Join Timer (JT) to expire after t_periodic seconds.
399 /* send Prune(S,G) to the old upstream neighbor */
400 pim_joinprune_send(old_interface
, old_rpf_addr
,
403 /* send Join(S,G) to the current upstream neighbor */
404 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
405 up
->rpf
.rpf_addr
.u
.prefix4
,
409 pim_upstream_join_timer_restart(up
);
410 } /* up->join_state == PIM_UPSTREAM_JOINED */
412 /* FIXME can join_desired actually be changed by pim_rpf_update()
413 returning PIM_RPF_CHANGED ? */
414 pim_upstream_update_join_desired(up
);
416 } /* PIM_RPF_CHANGED */
418 } /* for (qpim_upstream_list) */
423 pim_scan_individual_oil (struct channel_oil
*c_oil
)
425 struct in_addr vif_source
;
426 int input_iface_vif_index
;
429 if (!pim_rp_set_upstream_addr (&vif_source
, c_oil
->oil
.mfcc_origin
, c_oil
->oil
.mfcc_mcastgrp
))
432 input_iface_vif_index
= fib_lookup_if_vif_index (vif_source
);
433 if (input_iface_vif_index
< 1)
437 char source_str
[INET_ADDRSTRLEN
];
438 char group_str
[INET_ADDRSTRLEN
];
439 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
440 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
441 zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
442 __FILE__
, __PRETTY_FUNCTION__
, c_oil
->oil
.mfcc_parent
,
443 source_str
, group_str
);
445 pim_mroute_del (c_oil
, __PRETTY_FUNCTION__
);
449 if (input_iface_vif_index
== c_oil
->oil
.mfcc_parent
)
451 if (!c_oil
->installed
)
452 pim_mroute_add (c_oil
, __PRETTY_FUNCTION__
);
460 struct interface
*old_iif
= pim_if_find_by_vif_index(c_oil
->oil
.mfcc_parent
);
461 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
462 char source_str
[INET_ADDRSTRLEN
];
463 char group_str
[INET_ADDRSTRLEN
];
464 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
465 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
466 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
467 __FILE__
, __PRETTY_FUNCTION__
,
468 source_str
, group_str
,
469 old_iif
->name
, c_oil
->oil
.mfcc_parent
,
470 new_iif
->name
, input_iface_vif_index
);
473 /* new iif loops to existing oif ? */
474 if (c_oil
->oil
.mfcc_ttls
[input_iface_vif_index
])
476 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
478 if (PIM_DEBUG_ZEBRA
) {
479 char source_str
[INET_ADDRSTRLEN
];
480 char group_str
[INET_ADDRSTRLEN
];
481 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
482 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
483 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
484 __FILE__
, __PRETTY_FUNCTION__
,
485 source_str
, group_str
,
486 new_iif
->name
, input_iface_vif_index
);
489 //del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
492 /* update iif vif_index */
493 old_vif_index
= c_oil
->oil
.mfcc_parent
;
494 c_oil
->oil
.mfcc_parent
= input_iface_vif_index
;
496 /* update kernel multicast forwarding cache (MFC) */
497 if (pim_mroute_add(c_oil
, __PRETTY_FUNCTION__
))
499 if (PIM_DEBUG_MROUTE
)
501 /* just log warning */
502 struct interface
*old_iif
= pim_if_find_by_vif_index(old_vif_index
);
503 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
504 char source_str
[INET_ADDRSTRLEN
];
505 char group_str
[INET_ADDRSTRLEN
];
506 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
507 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
508 zlog_debug("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
509 __FILE__
, __PRETTY_FUNCTION__
,
510 source_str
, group_str
,
511 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
512 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
519 struct listnode
*node
;
520 struct listnode
*nextnode
;
521 struct channel_oil
*c_oil
;
523 qpim_scan_oil_last
= pim_time_monotonic_sec();
524 ++qpim_scan_oil_events
;
526 for (ALL_LIST_ELEMENTS(pim_channel_oil_list
, node
, nextnode
, c_oil
))
527 pim_scan_individual_oil (c_oil
);
530 static int on_rpf_cache_refresh(struct thread
*t
)
532 zassert(qpim_rpf_cache_refresher
);
534 qpim_rpf_cache_refresher
= 0;
536 /* update PIM protocol state */
537 scan_upstream_rpf_cache();
539 /* update kernel multicast forwarding cache (MFC) */
542 qpim_rpf_cache_refresh_last
= pim_time_monotonic_sec();
543 ++qpim_rpf_cache_refresh_events
;
549 void sched_rpf_cache_refresh(void)
551 ++qpim_rpf_cache_refresh_requests
;
553 pim_rpf_set_refresh_time ();
555 if (qpim_rpf_cache_refresher
) {
556 /* Refresh timer is already running */
560 /* Start refresh timer */
562 if (PIM_DEBUG_ZEBRA
) {
563 zlog_debug("%s: triggering %ld msec timer",
565 qpim_rpf_cache_refresh_delay_msec
);
568 THREAD_TIMER_MSEC_ON(master
, qpim_rpf_cache_refresher
,
569 on_rpf_cache_refresh
,
570 0, qpim_rpf_cache_refresh_delay_msec
);
573 static int redist_read_ipv4_route(int command
, struct zclient
*zclient
,
574 zebra_size_t length
, vrf_id_t vrf_id
)
577 struct zapi_ipv4 api
;
579 struct in_addr nexthop
;
580 struct prefix_ipv4 p
;
583 if (length
< min_len
) {
584 zlog_warn("%s %s: short buffer: length=%d min=%d",
585 __FILE__
, __PRETTY_FUNCTION__
,
594 /* Type, flags, message. */
595 api
.type
= stream_getc(s
);
596 api
.instance
= stream_getw (s
);
597 api
.flags
= stream_getl(s
);
598 api
.message
= stream_getc(s
);
600 /* IPv4 prefix length. */
601 memset(&p
, 0, sizeof(struct prefix_ipv4
));
603 p
.prefixlen
= stream_getc(s
);
607 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? 5 : 0 +
608 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? 5 : 0 +
609 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? 1 : 0 +
610 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? 4 : 0;
612 if (PIM_DEBUG_ZEBRA
) {
613 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
614 __FILE__
, __PRETTY_FUNCTION__
,
616 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
617 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
618 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
619 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
623 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
625 /* Nexthop, ifindex, distance, metric. */
626 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
627 api
.nexthop_num
= stream_getc(s
);
628 nexthop
.s_addr
= stream_get_ipv4(s
);
630 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
)) {
631 api
.ifindex_num
= stream_getc(s
);
632 ifindex
= stream_getl(s
);
635 api
.distance
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ?
639 api
.metric
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ?
643 if (CHECK_FLAG (api
.message
, ZAPI_MESSAGE_TAG
))
644 api
.tag
= stream_getl (s
);
649 case ZEBRA_REDISTRIBUTE_IPV4_ADD
:
650 if (PIM_DEBUG_ZEBRA
) {
651 char buf
[2][INET_ADDRSTRLEN
];
652 zlog_debug("%s: add %s %s/%d "
653 "nexthop %s ifindex %d metric%s %u distance%s %u",
655 zebra_route_string(api
.type
),
656 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
658 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
660 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
662 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
666 case ZEBRA_REDISTRIBUTE_IPV4_DEL
:
667 if (PIM_DEBUG_ZEBRA
) {
668 char buf
[2][INET_ADDRSTRLEN
];
669 zlog_debug("%s: delete %s %s/%d "
670 "nexthop %s ifindex %d metric%s %u distance%s %u",
672 zebra_route_string(api
.type
),
673 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
675 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
677 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
679 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
684 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__
, command
);
688 sched_rpf_cache_refresh();
695 pim_zebra_connected (struct zclient
*zclient
)
697 zclient_send_reg_requests (zclient
, VRF_DEFAULT
);
700 void pim_zebra_init(char *zebra_sock_path
)
705 zclient_serv_path_set(zebra_sock_path
);
707 #ifdef HAVE_TCP_ZEBRA
708 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT
);
710 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
713 /* Socket for receiving updates from Zebra daemon */
714 qpim_zclient_update
= zclient_new (master
);
716 qpim_zclient_update
->zebra_connected
= pim_zebra_connected
;
717 qpim_zclient_update
->router_id_update
= pim_router_id_update_zebra
;
718 qpim_zclient_update
->interface_add
= pim_zebra_if_add
;
719 qpim_zclient_update
->interface_delete
= pim_zebra_if_del
;
720 qpim_zclient_update
->interface_up
= pim_zebra_if_state_up
;
721 qpim_zclient_update
->interface_down
= pim_zebra_if_state_down
;
722 qpim_zclient_update
->interface_address_add
= pim_zebra_if_address_add
;
723 qpim_zclient_update
->interface_address_delete
= pim_zebra_if_address_del
;
724 qpim_zclient_update
->redistribute_route_ipv4_add
= redist_read_ipv4_route
;
725 qpim_zclient_update
->redistribute_route_ipv4_del
= redist_read_ipv4_route
;
727 zclient_init(qpim_zclient_update
, ZEBRA_ROUTE_PIM
, 0);
728 if (PIM_DEBUG_PIM_TRACE
) {
729 zlog_info("zclient_init cleared redistribution request");
732 zassert(qpim_zclient_update
->redist_default
== ZEBRA_ROUTE_PIM
);
734 /* Request all redistribution */
735 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
736 if (i
== qpim_zclient_update
->redist_default
)
738 vrf_bitmap_set (qpim_zclient_update
->redist
[AFI_IP
][i
], VRF_DEFAULT
);;
739 if (PIM_DEBUG_PIM_TRACE
) {
740 zlog_debug("%s: requesting redistribution for %s (%i)",
741 __PRETTY_FUNCTION__
, zebra_route_string(i
), i
);
745 /* Request default information */
746 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
747 qpim_zclient_update
, VRF_DEFAULT
);
749 if (PIM_DEBUG_PIM_TRACE
) {
750 zlog_info("%s: requesting default information redistribution",
751 __PRETTY_FUNCTION__
);
753 zlog_notice("%s: zclient update socket initialized",
754 __PRETTY_FUNCTION__
);
757 zclient_lookup_new();
760 void igmp_anysource_forward_start(struct igmp_group
*group
)
762 struct igmp_source
*source
;
763 struct in_addr src_addr
= { .s_addr
= 0 };
764 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
765 zassert(group
->group_filtermode_isexcl
);
766 zassert(listcount(group
->group_source_list
) < 1);
768 source
= source_new (group
, src_addr
);
771 zlog_warn ("%s: Failure to create * source", __PRETTY_FUNCTION__
);
775 igmp_source_forward_start (source
);
778 void igmp_anysource_forward_stop(struct igmp_group
*group
)
780 struct igmp_source
*source
;
781 struct in_addr star
= { .s_addr
= 0 };
783 source
= igmp_find_source_by_addr (group
, star
);
785 igmp_source_forward_stop (source
);
788 static int fib_lookup_if_vif_index(struct in_addr addr
)
790 struct pim_zlookup_nexthop nexthop_tab
[MULTIPATH_NUM
];
793 ifindex_t first_ifindex
;
795 num_ifindex
= zclient_lookup_nexthop(nexthop_tab
,
797 PIM_NEXTHOP_LOOKUP_MAX
);
798 if (num_ifindex
< 1) {
801 char addr_str
[INET_ADDRSTRLEN
];
802 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
803 zlog_debug("%s %s: could not find nexthop ifindex for address %s",
804 __FILE__
, __PRETTY_FUNCTION__
,
810 first_ifindex
= nexthop_tab
[0].ifindex
;
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: 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
);
821 /* debug warning only, do not return */
824 if (PIM_DEBUG_ZEBRA
) {
825 char addr_str
[INET_ADDRSTRLEN
];
826 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
827 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
828 __FILE__
, __PRETTY_FUNCTION__
,
829 first_ifindex
, ifindex2ifname(first_ifindex
), addr_str
);
832 vif_index
= pim_if_find_vifindex_by_ifindex(first_ifindex
);
837 char addr_str
[INET_ADDRSTRLEN
];
838 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
839 zlog_debug("%s %s: low vif_index=%d < 1 nexthop for address %s",
840 __FILE__
, __PRETTY_FUNCTION__
,
841 vif_index
, addr_str
);
849 static int del_oif(struct channel_oil
*channel_oil
,
850 struct interface
*oif
,
853 struct pim_interface
*pim_ifp
;
858 if (PIM_DEBUG_MROUTE
) {
859 char group_str
[INET_ADDRSTRLEN
];
860 char source_str
[INET_ADDRSTRLEN
];
861 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
862 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
863 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
864 __FILE__
, __PRETTY_FUNCTION__
,
865 source_str
, group_str
,
866 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
869 /* Prevent single protocol from unsubscribing same interface from
870 channel (S,G) multiple times */
871 if (!(channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & proto_mask
)) {
872 if (PIM_DEBUG_MROUTE
)
874 char group_str
[INET_ADDRSTRLEN
];
875 char source_str
[INET_ADDRSTRLEN
];
876 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
877 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
878 zlog_debug("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
879 __FILE__
, __PRETTY_FUNCTION__
,
880 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
881 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
882 source_str
, group_str
);
887 /* Mark that protocol is no longer interested in this OIF */
888 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] &= ~proto_mask
;
890 /* Allow multiple protocols to unsubscribe same interface from
891 channel (S,G) multiple times, by silently ignoring requests while
892 there is at least one protocol interested in the channel */
893 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
895 /* Check the OIF keeps existing before returning, and only log
897 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
898 if (PIM_DEBUG_MROUTE
)
900 char group_str
[INET_ADDRSTRLEN
];
901 char source_str
[INET_ADDRSTRLEN
];
902 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
903 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
904 zlog_debug("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
905 __FILE__
, __PRETTY_FUNCTION__
,
906 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
907 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
908 source_str
, group_str
);
915 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
918 if (PIM_DEBUG_MROUTE
)
920 char group_str
[INET_ADDRSTRLEN
];
921 char source_str
[INET_ADDRSTRLEN
];
922 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
923 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
924 zlog_debug("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
925 __FILE__
, __PRETTY_FUNCTION__
,
926 oif
->name
, pim_ifp
->mroute_vif_index
,
927 source_str
, group_str
);
932 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = 0;
934 if (pim_mroute_add(channel_oil
, __PRETTY_FUNCTION__
)) {
935 char group_str
[INET_ADDRSTRLEN
];
936 char source_str
[INET_ADDRSTRLEN
];
937 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
938 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
939 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
940 __FILE__
, __PRETTY_FUNCTION__
,
941 oif
->name
, pim_ifp
->mroute_vif_index
,
942 source_str
, group_str
);
944 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
948 --channel_oil
->oil_size
;
950 if (channel_oil
->oil_size
< 1) {
951 if (pim_mroute_del(channel_oil
, __PRETTY_FUNCTION__
)) {
952 if (PIM_DEBUG_MROUTE
)
954 /* just log a warning in case of failure */
955 char group_str
[INET_ADDRSTRLEN
];
956 char source_str
[INET_ADDRSTRLEN
];
957 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
958 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
959 zlog_debug("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
960 __FILE__
, __PRETTY_FUNCTION__
,
961 source_str
, group_str
);
966 if (PIM_DEBUG_MROUTE
) {
967 char group_str
[INET_ADDRSTRLEN
];
968 char source_str
[INET_ADDRSTRLEN
];
969 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
970 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
971 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
972 __FILE__
, __PRETTY_FUNCTION__
,
973 source_str
, group_str
,
974 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
980 void igmp_source_forward_start(struct igmp_source
*source
)
982 struct igmp_group
*group
;
986 memset (&sg
, 0, sizeof (struct prefix_sg
));
987 sg
.src
= source
->source_addr
;
988 sg
.grp
= source
->source_group
->group_addr
;
990 if (PIM_DEBUG_IGMP_TRACE
) {
991 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
993 pim_str_sg_dump (&sg
),
994 source
->source_group
->group_igmp_sock
->fd
,
995 source
->source_group
->group_igmp_sock
->interface
->name
,
996 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
999 /* Prevent IGMP interface from installing multicast route multiple
1001 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1005 group
= source
->source_group
;
1007 if (!source
->source_channel_oil
) {
1008 struct in_addr vif_source
;
1009 struct pim_interface
*pim_oif
;
1011 if (!pim_rp_set_upstream_addr (&vif_source
, source
->source_addr
, sg
.grp
))
1014 int input_iface_vif_index
= fib_lookup_if_vif_index(vif_source
);
1015 if (input_iface_vif_index
< 1) {
1016 if (PIM_DEBUG_IGMP_TRACE
)
1018 char source_str
[INET_ADDRSTRLEN
];
1019 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1020 zlog_debug("%s %s: could not find input interface for source %s",
1021 __FILE__
, __PRETTY_FUNCTION__
,
1028 Protect IGMP against adding looped MFC entries created by both
1029 source and receiver attached to the same interface. See TODO
1032 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
1034 if (PIM_DEBUG_IGMP_TRACE
)
1036 zlog_debug("%s: multicast not enabled on oif=%s ?",
1037 __PRETTY_FUNCTION__
,
1038 source
->source_group
->group_igmp_sock
->interface
->name
);
1043 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
1044 /* ignore request for looped MFC entry */
1045 if (PIM_DEBUG_IGMP_TRACE
) {
1046 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%s: igmp_sock=%d oif=%s vif_index=%d",
1047 __PRETTY_FUNCTION__
,
1048 pim_str_sg_dump (&sg
),
1049 source
->source_group
->group_igmp_sock
->fd
,
1050 source
->source_group
->group_igmp_sock
->interface
->name
,
1051 input_iface_vif_index
);
1056 source
->source_channel_oil
= pim_channel_oil_add(&sg
,
1057 input_iface_vif_index
);
1058 if (!source
->source_channel_oil
) {
1059 if (PIM_DEBUG_IGMP_TRACE
)
1061 zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
1062 __FILE__
, __PRETTY_FUNCTION__
,
1063 pim_str_sg_dump (&sg
));
1069 result
= pim_channel_add_oif(source
->source_channel_oil
,
1070 group
->group_igmp_sock
->interface
,
1071 PIM_OIF_FLAG_PROTO_IGMP
);
1073 if (PIM_DEBUG_MROUTE
)
1075 zlog_warn("%s: add_oif() failed with return=%d",
1082 Feed IGMPv3-gathered local membership information into PIM
1083 per-interface (S,G) state.
1085 pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
, &sg
);
1087 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1091 igmp_source_forward_stop: stop fowarding, but keep the source
1092 igmp_source_delete: stop fowarding, and delete the source
1094 void igmp_source_forward_stop(struct igmp_source
*source
)
1096 struct igmp_group
*group
;
1097 struct prefix_sg sg
;
1100 memset (&sg
, 0, sizeof (struct prefix_sg
));
1101 sg
.src
= source
->source_addr
;
1102 sg
.grp
= source
->source_group
->group_addr
;
1104 if (PIM_DEBUG_IGMP_TRACE
) {
1105 zlog_debug("%s: (S,G)=%s igmp_sock=%d oif=%s fwd=%d",
1106 __PRETTY_FUNCTION__
,
1107 pim_str_sg_dump (&sg
),
1108 source
->source_group
->group_igmp_sock
->fd
,
1109 source
->source_group
->group_igmp_sock
->interface
->name
,
1110 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1113 /* Prevent IGMP interface from removing multicast route multiple
1115 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1119 group
= source
->source_group
;
1122 It appears that in certain circumstances that
1123 igmp_source_forward_stop is called when IGMP forwarding
1124 was not enabled in oif_flags for this outgoing interface.
1125 Possibly because of multiple calls. When that happens, we
1126 enter the below if statement and this function returns early
1127 which in turn triggers the calling function to assert.
1128 Making the call to del_oif and ignoring the return code
1129 fixes the issue without ill effect, similar to
1130 pim_forward_stop below.
1132 result
= del_oif(source
->source_channel_oil
,
1133 group
->group_igmp_sock
->interface
,
1134 PIM_OIF_FLAG_PROTO_IGMP
);
1136 if (PIM_DEBUG_IGMP_TRACE
)
1137 zlog_debug("%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
[INET_ADDRSTRLEN
];
1158 char group_str
[INET_ADDRSTRLEN
];
1159 char upstream_str
[INET_ADDRSTRLEN
];
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 if (PIM_DEBUG_PIM_TRACE
)
1174 char source_str
[INET_ADDRSTRLEN
];
1175 pim_inet4_dump("<source?>", up
->sg
.src
, source_str
, sizeof(source_str
));
1176 zlog_debug("%s %s: could not find input interface for source %s",
1177 __FILE__
, __PRETTY_FUNCTION__
,
1183 up
->channel_oil
= pim_channel_oil_add(&up
->sg
,
1184 input_iface_vif_index
);
1185 if (!up
->channel_oil
) {
1186 if (PIM_DEBUG_PIM_TRACE
)
1187 zlog_debug("%s %s: could not create OIL for channel (S,G)=%s",
1188 __FILE__
, __PRETTY_FUNCTION__
,
1194 pim_channel_add_oif(up
->channel_oil
,
1196 PIM_OIF_FLAG_PROTO_PIM
);
1199 void pim_forward_stop(struct pim_ifchannel
*ch
)
1201 struct pim_upstream
*up
= ch
->upstream
;
1203 if (PIM_DEBUG_PIM_TRACE
) {
1204 zlog_debug("%s: (S,G)=%s oif=%s",
1205 __PRETTY_FUNCTION__
,
1206 ch
->sg_str
, ch
->interface
->name
);
1209 if (!up
->channel_oil
) {
1210 if (PIM_DEBUG_PIM_TRACE
)
1211 zlog_debug("%s: (S,G)=%s oif=%s missing channel OIL",
1212 __PRETTY_FUNCTION__
,
1213 ch
->sg_str
, ch
->interface
->name
);
1218 del_oif(up
->channel_oil
,
1220 PIM_OIF_FLAG_PROTO_PIM
);