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,
20 $QuaggaId: $Format:%an, %ai, %h$ $
25 #include "zebra/rib.h"
36 #include "pim_zebra.h"
37 #include "pim_iface.h"
43 #include "pim_zlookup.h"
44 #include "pim_ifchannel.h"
47 #undef PIM_DEBUG_IFADDR_DUMP
48 #define PIM_DEBUG_IFADDR_DUMP
50 static int fib_lookup_if_vif_index(struct in_addr addr
);
51 static int del_oif(struct channel_oil
*channel_oil
,
52 struct interface
*oif
,
55 /* Router-id update message from zebra. */
56 static int pim_router_id_update_zebra(int command
, struct zclient
*zclient
,
57 zebra_size_t length
, vrf_id_t vrf_id
)
59 struct prefix router_id
;
61 zebra_router_id_update_read(zclient
->ibuf
, &router_id
);
66 static int pim_zebra_if_add(int command
, struct zclient
*zclient
,
67 zebra_size_t length
, vrf_id_t vrf_id
)
69 struct interface
*ifp
;
72 zebra api adds/dels interfaces using the same call
73 interface_add_read below, see comments in lib/zclient.c
75 ifp
= zebra_interface_add_read(zclient
->ibuf
, vrf_id
);
79 if (PIM_DEBUG_ZEBRA
) {
80 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
82 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
83 ifp
->mtu
, if_is_operative(ifp
));
86 if (if_is_operative(ifp
))
87 pim_if_addr_add_all(ifp
);
92 static int pim_zebra_if_del(int command
, struct zclient
*zclient
,
93 zebra_size_t length
, vrf_id_t vrf_id
)
95 struct interface
*ifp
;
98 zebra api adds/dels interfaces using the same call
99 interface_add_read below, see comments in lib/zclient.c
101 comments in lib/zclient.c seem to indicate that calling
102 zebra_interface_add_read is the correct call, but that
103 results in an attemted out of bounds read which causes
104 pimd to assert. Other clients use zebra_interface_state_read
105 and it appears to work just fine.
107 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
111 if (PIM_DEBUG_ZEBRA
) {
112 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
114 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
115 ifp
->mtu
, if_is_operative(ifp
));
118 if (!if_is_operative(ifp
))
119 pim_if_addr_del_all(ifp
);
124 static int pim_zebra_if_state_up(int command
, struct zclient
*zclient
,
125 zebra_size_t length
, vrf_id_t vrf_id
)
127 struct interface
*ifp
;
130 zebra api notifies interface up/down events by using the same call
131 zebra_interface_state_read below, see comments in lib/zclient.c
133 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
137 if (PIM_DEBUG_ZEBRA
) {
138 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
140 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
141 ifp
->mtu
, if_is_operative(ifp
));
144 if (if_is_operative(ifp
)) {
146 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
148 pim_if_addr_add_all(ifp
);
154 static int pim_zebra_if_state_down(int command
, struct zclient
*zclient
,
155 zebra_size_t length
, vrf_id_t vrf_id
)
157 struct interface
*ifp
;
160 zebra api notifies interface up/down events by using the same call
161 zebra_interface_state_read below, see comments in lib/zclient.c
163 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
167 if (PIM_DEBUG_ZEBRA
) {
168 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
170 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
171 ifp
->mtu
, if_is_operative(ifp
));
174 if (!if_is_operative(ifp
)) {
176 pim_if_addr_del_all() suffices for shutting down IGMP,
177 but not for shutting down PIM
179 pim_if_addr_del_all(ifp
);
182 pim_sock_delete() closes the socket, stops read and timer threads,
183 and kills all neighbors.
186 pim_sock_delete(ifp
, "link down");
193 #ifdef PIM_DEBUG_IFADDR_DUMP
194 static void dump_if_address(struct interface
*ifp
)
196 struct connected
*ifc
;
197 struct listnode
*node
;
199 zlog_debug("%s %s: interface %s addresses:",
200 __FILE__
, __PRETTY_FUNCTION__
,
203 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
204 struct prefix
*p
= ifc
->address
;
206 if (p
->family
!= AF_INET
)
209 zlog_debug("%s %s: interface %s address %s %s",
210 __FILE__
, __PRETTY_FUNCTION__
,
212 inet_ntoa(p
->u
.prefix4
),
213 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
214 "secondary" : "primary");
219 static int pim_zebra_if_address_add(int command
, struct zclient
*zclient
,
220 zebra_size_t length
, vrf_id_t vrf_id
)
224 struct in_addr old
= { .s_addr
= 0 };
227 zebra api notifies address adds/dels events by using the same call
228 interface_add_read below, see comments in lib/zclient.c
230 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
231 will add address to interface list by calling
232 connected_add_by_prefix()
234 c
= zebra_interface_address_read(command
, zclient
->ibuf
, vrf_id
);
239 if (p
->family
!= AF_INET
)
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 pim_rp_check_rp (old
, p
->u
.prefix4
);
257 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
258 /* trying to add primary address */
260 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
261 if (primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
262 if (PIM_DEBUG_ZEBRA
) {
263 /* but we had a primary address already */
268 prefix2str(p
, buf
, BUFSIZ
);
269 pim_inet4_dump("<old?>", primary_addr
, old
, sizeof(old
));
271 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
273 c
->ifp
->name
, old
, buf
);
275 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
284 static int pim_zebra_if_address_del(int command
, struct zclient
*client
,
285 zebra_size_t length
, vrf_id_t vrf_id
)
289 struct in_addr
new = { .s_addr
= 0 };
292 zebra api notifies address adds/dels events by using the same call
293 interface_add_read below, see comments in lib/zclient.c
295 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
296 will remove address from interface list by calling
297 connected_delete_by_prefix()
299 c
= zebra_interface_address_read(command
, client
->ibuf
, vrf_id
);
304 if (p
->family
!= AF_INET
)
307 if (PIM_DEBUG_ZEBRA
) {
309 prefix2str(p
, buf
, BUFSIZ
);
310 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
312 c
->ifp
->name
, buf
, c
->flags
,
313 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
315 #ifdef PIM_DEBUG_IFADDR_DUMP
316 dump_if_address(c
->ifp
);
320 pim_rp_check_rp (p
->u
.prefix4
, new);
321 pim_if_addr_del(c
, 0);
326 static void scan_upstream_rpf_cache()
328 struct listnode
*up_node
;
329 struct listnode
*up_nextnode
;
330 struct pim_upstream
*up
;
332 for (ALL_LIST_ELEMENTS(qpim_upstream_list
, up_node
, up_nextnode
, up
)) {
333 struct in_addr old_rpf_addr
;
334 enum pim_rpf_result rpf_result
;
336 rpf_result
= pim_rpf_update(up
, &old_rpf_addr
, NULL
);
337 if (rpf_result
== PIM_RPF_FAILURE
)
340 if (rpf_result
== PIM_RPF_CHANGED
) {
342 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
345 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
347 Transitions from Joined State
349 RPF'(S,G) changes not due to an Assert
351 The upstream (S,G) state machine remains in Joined
352 state. Send Join(S,G) to the new upstream neighbor, which is
353 the new value of RPF'(S,G). Send Prune(S,G) to the old
354 upstream neighbor, which is the old value of RPF'(S,G). Set
355 the Join Timer (JT) to expire after t_periodic seconds.
359 /* send Prune(S,G) to the old upstream neighbor */
360 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
366 /* send Join(S,G) to the current upstream neighbor */
367 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
373 pim_upstream_join_timer_restart(up
);
374 } /* up->join_state == PIM_UPSTREAM_JOINED */
376 /* FIXME can join_desired actually be changed by pim_rpf_update()
377 returning PIM_RPF_CHANGED ? */
378 pim_upstream_update_join_desired(up
);
380 } /* PIM_RPF_CHANGED */
382 } /* for (qpim_upstream_list) */
388 struct listnode
*node
;
389 struct listnode
*nextnode
;
390 struct channel_oil
*c_oil
;
392 qpim_scan_oil_last
= pim_time_monotonic_sec();
393 ++qpim_scan_oil_events
;
395 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list
, node
, nextnode
, c_oil
)) {
397 int input_iface_vif_index
= fib_lookup_if_vif_index(c_oil
->oil
.mfcc_origin
);
398 if (input_iface_vif_index
< 1) {
399 char source_str
[100];
401 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
402 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
403 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
404 __FILE__
, __PRETTY_FUNCTION__
,
405 source_str
, group_str
);
409 if (input_iface_vif_index
== c_oil
->oil
.mfcc_parent
) {
414 if (PIM_DEBUG_ZEBRA
) {
415 struct interface
*old_iif
= pim_if_find_by_vif_index(c_oil
->oil
.mfcc_parent
);
416 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
417 char source_str
[100];
419 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
420 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
421 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
422 __FILE__
, __PRETTY_FUNCTION__
,
423 source_str
, group_str
,
424 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
425 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
428 /* new iif loops to existing oif ? */
429 if (c_oil
->oil
.mfcc_ttls
[input_iface_vif_index
]) {
430 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
432 if (PIM_DEBUG_ZEBRA
) {
433 char source_str
[100];
435 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
436 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
437 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
438 __FILE__
, __PRETTY_FUNCTION__
,
439 source_str
, group_str
,
440 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
443 del_oif(c_oil
, new_iif
, PIM_OIF_FLAG_PROTO_ANY
);
446 /* update iif vif_index */
447 old_vif_index
= c_oil
->oil
.mfcc_parent
;
448 c_oil
->oil
.mfcc_parent
= input_iface_vif_index
;
450 /* update kernel multicast forwarding cache (MFC) */
451 if (pim_mroute_add(&c_oil
->oil
)) {
452 /* just log warning */
453 struct interface
*old_iif
= pim_if_find_by_vif_index(old_vif_index
);
454 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
455 char source_str
[100];
457 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
458 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
459 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
460 __FILE__
, __PRETTY_FUNCTION__
,
461 source_str
, group_str
,
462 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
463 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
467 } /* for (qpim_channel_oil_list) */
470 static int on_rpf_cache_refresh(struct thread
*t
)
473 zassert(qpim_rpf_cache_refresher
);
475 qpim_rpf_cache_refresher
= 0;
477 /* update PIM protocol state */
478 scan_upstream_rpf_cache();
480 /* update kernel multicast forwarding cache (MFC) */
483 qpim_rpf_cache_refresh_last
= pim_time_monotonic_sec();
484 ++qpim_rpf_cache_refresh_events
;
489 static void sched_rpf_cache_refresh()
491 ++qpim_rpf_cache_refresh_requests
;
493 if (qpim_rpf_cache_refresher
) {
494 /* Refresh timer is already running */
498 /* Start refresh timer */
500 if (PIM_DEBUG_ZEBRA
) {
501 zlog_debug("%s: triggering %ld msec timer",
503 qpim_rpf_cache_refresh_delay_msec
);
506 THREAD_TIMER_MSEC_ON(master
, qpim_rpf_cache_refresher
,
507 on_rpf_cache_refresh
,
508 0, qpim_rpf_cache_refresh_delay_msec
);
511 static int redist_read_ipv4_route(int command
, struct zclient
*zclient
,
512 zebra_size_t length
, vrf_id_t vrf_id
)
515 struct zapi_ipv4 api
;
516 unsigned long ifindex
;
517 struct in_addr nexthop
;
518 struct prefix_ipv4 p
;
521 if (length
< min_len
) {
522 zlog_warn("%s %s: short buffer: length=%d min=%d",
523 __FILE__
, __PRETTY_FUNCTION__
,
532 /* Type, flags, message. */
533 api
.type
= stream_getc(s
);
534 api
.instance
= stream_getw (s
);
535 api
.flags
= stream_getc(s
);
536 api
.message
= stream_getc(s
);
538 /* IPv4 prefix length. */
539 memset(&p
, 0, sizeof(struct prefix_ipv4
));
541 p
.prefixlen
= stream_getc(s
);
545 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? 5 : 0 +
546 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? 5 : 0 +
547 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? 1 : 0 +
548 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? 4 : 0;
550 if (PIM_DEBUG_ZEBRA
) {
551 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
552 __FILE__
, __PRETTY_FUNCTION__
,
554 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
555 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
556 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
557 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
560 if (length
< min_len
) {
561 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
562 __FILE__
, __PRETTY_FUNCTION__
,
564 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
565 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
566 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
567 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
572 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
574 /* Nexthop, ifindex, distance, metric. */
575 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
576 api
.nexthop_num
= stream_getc(s
);
577 nexthop
.s_addr
= stream_get_ipv4(s
);
579 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
)) {
580 api
.ifindex_num
= stream_getc(s
);
581 ifindex
= stream_getl(s
);
584 api
.distance
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ?
588 api
.metric
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ?
592 if (CHECK_FLAG (api
.message
, ZAPI_MESSAGE_TAG
))
593 api
.tag
= stream_getw (s
);
598 case ZEBRA_REDISTRIBUTE_IPV4_ADD
:
599 case ZEBRA_IPV4_ROUTE_ADD
:
600 if (PIM_DEBUG_ZEBRA
) {
601 char buf
[2][INET_ADDRSTRLEN
];
602 zlog_debug("%s: add %s %s/%d "
603 "nexthop %s ifindex %ld metric%s %u distance%s %u",
605 zebra_route_string(api
.type
),
606 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
608 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
610 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
612 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
616 case ZEBRA_REDISTRIBUTE_IPV4_DEL
:
617 case ZEBRA_IPV4_ROUTE_DELETE
:
618 if (PIM_DEBUG_ZEBRA
) {
619 char buf
[2][INET_ADDRSTRLEN
];
620 zlog_debug("%s: delete %s %s/%d "
621 "nexthop %s ifindex %ld metric%s %u distance%s %u",
623 zebra_route_string(api
.type
),
624 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
626 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
628 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
630 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
635 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__
, command
);
639 sched_rpf_cache_refresh();
645 pim_zebra_connected (struct zclient
*zclient
)
647 zclient_send_reg_requests (zclient
, VRF_DEFAULT
);
649 void pim_zebra_init(char *zebra_sock_path
)
654 zclient_serv_path_set(zebra_sock_path
);
656 #ifdef HAVE_TCP_ZEBRA
657 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT
);
659 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
662 /* Socket for receiving updates from Zebra daemon */
663 qpim_zclient_update
= zclient_new (master
);
665 qpim_zclient_update
->zebra_connected
= pim_zebra_connected
;
666 qpim_zclient_update
->router_id_update
= pim_router_id_update_zebra
;
667 qpim_zclient_update
->interface_add
= pim_zebra_if_add
;
668 qpim_zclient_update
->interface_delete
= pim_zebra_if_del
;
669 qpim_zclient_update
->interface_up
= pim_zebra_if_state_up
;
670 qpim_zclient_update
->interface_down
= pim_zebra_if_state_down
;
671 qpim_zclient_update
->interface_address_add
= pim_zebra_if_address_add
;
672 qpim_zclient_update
->interface_address_delete
= pim_zebra_if_address_del
;
673 qpim_zclient_update
->ipv4_route_add
= redist_read_ipv4_route
;
674 qpim_zclient_update
->ipv4_route_delete
= redist_read_ipv4_route
;
675 qpim_zclient_update
->redistribute_route_ipv4_add
= redist_read_ipv4_route
;
676 qpim_zclient_update
->redistribute_route_ipv4_del
= redist_read_ipv4_route
;
678 zclient_init(qpim_zclient_update
, ZEBRA_ROUTE_PIM
, 0);
679 if (PIM_DEBUG_PIM_TRACE
) {
680 zlog_info("zclient_init cleared redistribution request");
683 zassert(qpim_zclient_update
->redist_default
== ZEBRA_ROUTE_PIM
);
685 /* Request all redistribution */
686 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
687 if (i
== qpim_zclient_update
->redist_default
)
689 vrf_bitmap_set (qpim_zclient_update
->redist
[AFI_IP
][i
], VRF_DEFAULT
);;
690 if (PIM_DEBUG_PIM_TRACE
) {
691 zlog_debug("%s: requesting redistribution for %s (%i)",
692 __PRETTY_FUNCTION__
, zebra_route_string(i
), i
);
696 /* Request default information */
697 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
698 qpim_zclient_update
, VRF_DEFAULT
);
700 if (PIM_DEBUG_PIM_TRACE
) {
701 zlog_info("%s: requesting default information redistribution",
702 __PRETTY_FUNCTION__
);
704 zlog_notice("%s: zclient update socket initialized",
705 __PRETTY_FUNCTION__
);
708 zassert(!qpim_zclient_lookup
);
709 qpim_zclient_lookup
= zclient_lookup_new();
710 zassert(qpim_zclient_lookup
);
713 void igmp_anysource_forward_start(struct igmp_group
*group
)
715 struct igmp_source
*source
;
716 struct in_addr src_addr
= { .s_addr
= 0 };
717 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
718 zassert(group
->group_filtermode_isexcl
);
719 zassert(listcount(group
->group_source_list
) < 1);
721 source
= source_new (group
, src_addr
);
724 zlog_warn ("%s: Failure to create * source", __PRETTY_FUNCTION__
);
728 igmp_source_forward_start (source
);
731 void igmp_anysource_forward_stop(struct igmp_group
*group
)
733 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
734 zassert((!group
->group_filtermode_isexcl
) || (listcount(group
->group_source_list
) > 0));
736 if (PIM_DEBUG_IGMP_TRACE
) {
737 zlog_debug("%s %s: UNIMPLEMENTED",
738 __FILE__
, __PRETTY_FUNCTION__
);
742 static int fib_lookup_if_vif_index(struct in_addr addr
)
744 struct pim_zlookup_nexthop nexthop_tab
[PIM_NEXTHOP_IFINDEX_TAB_SIZE
];
749 num_ifindex
= zclient_lookup_nexthop(qpim_zclient_lookup
, nexthop_tab
,
750 PIM_NEXTHOP_IFINDEX_TAB_SIZE
, addr
,
751 PIM_NEXTHOP_LOOKUP_MAX
);
752 if (num_ifindex
< 1) {
754 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
755 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
756 __FILE__
, __PRETTY_FUNCTION__
,
761 first_ifindex
= nexthop_tab
[0].ifindex
;
763 if (num_ifindex
> 1) {
765 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
766 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
767 __FILE__
, __PRETTY_FUNCTION__
,
768 num_ifindex
, addr_str
, first_ifindex
);
769 /* debug warning only, do not return */
772 if (PIM_DEBUG_ZEBRA
) {
774 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
775 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
776 __FILE__
, __PRETTY_FUNCTION__
,
777 first_ifindex
, ifindex2ifname(first_ifindex
), addr_str
);
780 vif_index
= pim_if_find_vifindex_by_ifindex(first_ifindex
);
784 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
785 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
786 __FILE__
, __PRETTY_FUNCTION__
,
787 vif_index
, addr_str
);
791 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
793 if (vif_index
> qpim_mroute_oif_highest_vif_index
) {
795 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
796 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
797 __FILE__
, __PRETTY_FUNCTION__
,
798 vif_index
, qpim_mroute_oif_highest_vif_index
, addr_str
);
800 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
801 __FILE__
, __PRETTY_FUNCTION__
,
802 ifindex2ifname(vif_index
),
811 static int del_oif(struct channel_oil
*channel_oil
,
812 struct interface
*oif
,
815 struct pim_interface
*pim_ifp
;
818 zassert(channel_oil
);
822 zassert(pim_ifp
->mroute_vif_index
>= 1);
823 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
824 zassert(pim_ifp
->mroute_vif_index
<= qpim_mroute_oif_highest_vif_index
);
826 if (PIM_DEBUG_MROUTE
) {
828 char source_str
[100];
829 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
830 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
831 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
832 __FILE__
, __PRETTY_FUNCTION__
,
833 source_str
, group_str
,
834 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
837 /* Prevent single protocol from unsubscribing same interface from
838 channel (S,G) multiple times */
839 if (!(channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & proto_mask
)) {
841 char source_str
[100];
842 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
843 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
844 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
845 __FILE__
, __PRETTY_FUNCTION__
,
846 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
847 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
848 source_str
, group_str
);
852 /* Mark that protocol is no longer interested in this OIF */
853 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] &= ~proto_mask
;
855 /* Allow multiple protocols to unsubscribe same interface from
856 channel (S,G) multiple times, by silently ignoring requests while
857 there is at least one protocol interested in the channel */
858 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
860 /* Check the OIF keeps existing before returning, and only log
862 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
864 char source_str
[100];
865 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
866 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
867 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
868 __FILE__
, __PRETTY_FUNCTION__
,
869 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
870 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
871 source_str
, group_str
);
877 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
881 char source_str
[100];
882 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
883 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
884 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
885 __FILE__
, __PRETTY_FUNCTION__
,
886 oif
->name
, pim_ifp
->mroute_vif_index
,
887 source_str
, group_str
);
891 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = 0;
893 if (pim_mroute_add(&channel_oil
->oil
)) {
895 char source_str
[100];
896 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
897 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
898 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
899 __FILE__
, __PRETTY_FUNCTION__
,
900 oif
->name
, pim_ifp
->mroute_vif_index
,
901 source_str
, group_str
);
903 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
907 --channel_oil
->oil_size
;
909 if (channel_oil
->oil_size
< 1) {
910 if (pim_mroute_del(&channel_oil
->oil
)) {
911 /* just log a warning in case of failure */
913 char source_str
[100];
914 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
915 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
916 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
917 __FILE__
, __PRETTY_FUNCTION__
,
918 source_str
, group_str
);
922 if (PIM_DEBUG_MROUTE
) {
924 char source_str
[100];
925 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
926 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
927 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
928 __FILE__
, __PRETTY_FUNCTION__
,
929 source_str
, group_str
,
930 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
936 void igmp_source_forward_start(struct igmp_source
*source
)
938 struct igmp_group
*group
;
941 if (PIM_DEBUG_IGMP_TRACE
) {
942 char source_str
[100];
944 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
945 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
946 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
948 source_str
, group_str
,
949 source
->source_group
->group_igmp_sock
->fd
,
950 source
->source_group
->group_igmp_sock
->interface
->name
,
951 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
954 /* Prevent IGMP interface from installing multicast route multiple
956 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
960 group
= source
->source_group
;
962 if (!source
->source_channel_oil
) {
963 struct in_addr vif_source
;
964 struct pim_interface
*pim_oif
;
966 if (!pim_rp_set_upstream_addr (&vif_source
, source
->source_addr
))
969 int input_iface_vif_index
= fib_lookup_if_vif_index(vif_source
);
970 if (input_iface_vif_index
< 1) {
971 char source_str
[100];
972 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
973 zlog_warn("%s %s: could not find input interface for source %s",
974 __FILE__
, __PRETTY_FUNCTION__
,
980 Protect IGMP against adding looped MFC entries created by both
981 source and receiver attached to the same interface. See TODO
984 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
986 zlog_warn("%s: multicast not enabled on oif=%s ?",
988 source
->source_group
->group_igmp_sock
->interface
->name
);
991 if (pim_oif
->mroute_vif_index
< 1) {
992 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
993 __FILE__
, __PRETTY_FUNCTION__
,
994 source
->source_group
->group_igmp_sock
->interface
->name
,
995 pim_oif
->mroute_vif_index
);
998 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
999 /* ignore request for looped MFC entry */
1000 if (PIM_DEBUG_IGMP_TRACE
) {
1001 char source_str
[100];
1002 char group_str
[100];
1003 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1004 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1005 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1006 __PRETTY_FUNCTION__
,
1007 source_str
, group_str
,
1008 source
->source_group
->group_igmp_sock
->fd
,
1009 source
->source_group
->group_igmp_sock
->interface
->name
,
1010 input_iface_vif_index
);
1015 source
->source_channel_oil
= pim_channel_oil_add(group
->group_addr
,
1016 source
->source_addr
,
1017 input_iface_vif_index
);
1018 if (!source
->source_channel_oil
) {
1019 char group_str
[100];
1020 char source_str
[100];
1021 pim_inet4_dump("<group?>", group
->group_addr
, group_str
, sizeof(group_str
));
1022 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1023 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1024 __FILE__
, __PRETTY_FUNCTION__
,
1025 source_str
, group_str
);
1030 result
= pim_channel_add_oif(source
->source_channel_oil
,
1031 group
->group_igmp_sock
->interface
,
1032 PIM_OIF_FLAG_PROTO_IGMP
);
1034 zlog_warn("%s: add_oif() failed with return=%d",
1040 Feed IGMPv3-gathered local membership information into PIM
1041 per-interface (S,G) state.
1043 pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
,
1044 source
->source_addr
, group
->group_addr
);
1046 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1050 igmp_source_forward_stop: stop fowarding, but keep the source
1051 igmp_source_delete: stop fowarding, and delete the source
1053 void igmp_source_forward_stop(struct igmp_source
*source
)
1055 struct igmp_group
*group
;
1058 if (PIM_DEBUG_IGMP_TRACE
) {
1059 char source_str
[100];
1060 char group_str
[100];
1061 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1062 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1063 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1064 __PRETTY_FUNCTION__
,
1065 source_str
, group_str
,
1066 source
->source_group
->group_igmp_sock
->fd
,
1067 source
->source_group
->group_igmp_sock
->interface
->name
,
1068 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1071 /* Prevent IGMP interface from removing multicast route multiple
1073 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1077 group
= source
->source_group
;
1080 It appears that in certain circumstances that
1081 igmp_source_forward_stop is called when IGMP forwarding
1082 was not enabled in oif_flags for this outgoing interface.
1083 Possibly because of multiple calls. When that happens, we
1084 enter the below if statement and this function returns early
1085 which in turn triggers the calling function to assert.
1086 Making the call to del_oif and ignoring the return code
1087 fixes the issue without ill effect, similar to
1088 pim_forward_stop below.
1090 result
= del_oif(source
->source_channel_oil
,
1091 group
->group_igmp_sock
->interface
,
1092 PIM_OIF_FLAG_PROTO_IGMP
);
1094 zlog_warn("%s: del_oif() failed with return=%d",
1100 Feed IGMPv3-gathered local membership information into PIM
1101 per-interface (S,G) state.
1103 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1104 source
->source_addr
, group
->group_addr
);
1106 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1109 void pim_forward_start(struct pim_ifchannel
*ch
)
1111 struct pim_upstream
*up
= ch
->upstream
;
1113 if (PIM_DEBUG_PIM_TRACE
) {
1114 char source_str
[100];
1115 char group_str
[100];
1116 char upstream_str
[100];
1118 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1119 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1120 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
, sizeof(upstream_str
));
1121 zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
1122 __PRETTY_FUNCTION__
,
1123 source_str
, group_str
, ch
->interface
->name
, upstream_str
);
1126 if (!up
->channel_oil
) {
1127 int input_iface_vif_index
= fib_lookup_if_vif_index(up
->upstream_addr
);
1128 if (input_iface_vif_index
< 1) {
1129 char source_str
[100];
1130 pim_inet4_dump("<source?>", up
->source_addr
, source_str
, sizeof(source_str
));
1131 zlog_warn("%s %s: could not find input interface for source %s",
1132 __FILE__
, __PRETTY_FUNCTION__
,
1137 up
->channel_oil
= pim_channel_oil_add(up
->group_addr
, up
->source_addr
,
1138 input_iface_vif_index
);
1139 if (!up
->channel_oil
) {
1140 char group_str
[100];
1141 char source_str
[100];
1142 pim_inet4_dump("<group?>", up
->group_addr
, group_str
, sizeof(group_str
));
1143 pim_inet4_dump("<source?>", up
->source_addr
, source_str
, sizeof(source_str
));
1144 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1145 __FILE__
, __PRETTY_FUNCTION__
,
1146 source_str
, group_str
);
1151 pim_channel_add_oif(up
->channel_oil
,
1153 PIM_OIF_FLAG_PROTO_PIM
);
1156 void pim_forward_stop(struct pim_ifchannel
*ch
)
1158 struct pim_upstream
*up
= ch
->upstream
;
1160 if (PIM_DEBUG_PIM_TRACE
) {
1161 char source_str
[100];
1162 char group_str
[100];
1163 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1164 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1165 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1166 __PRETTY_FUNCTION__
,
1167 source_str
, group_str
, ch
->interface
->name
);
1170 if (!up
->channel_oil
) {
1171 char source_str
[100];
1172 char group_str
[100];
1173 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1174 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1175 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1176 __PRETTY_FUNCTION__
,
1177 source_str
, group_str
, ch
->interface
->name
);
1182 del_oif(up
->channel_oil
,
1184 PIM_OIF_FLAG_PROTO_PIM
);