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"
46 #undef PIM_DEBUG_IFADDR_DUMP
47 #define PIM_DEBUG_IFADDR_DUMP
49 static int fib_lookup_if_vif_index(struct in_addr addr
);
50 static int del_oif(struct channel_oil
*channel_oil
,
51 struct interface
*oif
,
54 static void zclient_broken(struct zclient
*zclient
)
56 struct listnode
*ifnode
;
57 struct interface
*ifp
;
59 zlog_warn("%s %s: broken zclient connection",
60 __FILE__
, __PRETTY_FUNCTION__
);
62 for (ALL_LIST_ELEMENTS_RO(iflist
, ifnode
, ifp
)) {
63 pim_if_addr_del_all(ifp
);
66 /* upon return, zclient will discard connected addresses */
69 /* Router-id update message from zebra. */
70 static int pim_router_id_update_zebra(int command
, struct zclient
*zclient
,
73 struct prefix router_id
;
75 zebra_router_id_update_read(zclient
->ibuf
, &router_id
);
80 static int pim_zebra_if_add(int command
, struct zclient
*zclient
,
83 struct interface
*ifp
;
86 zebra api adds/dels interfaces using the same call
87 interface_add_read below, see comments in lib/zclient.c
89 ifp
= zebra_interface_add_read(zclient
->ibuf
);
93 if (PIM_DEBUG_ZEBRA
) {
94 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
96 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
97 ifp
->mtu
, if_is_operative(ifp
));
100 if (if_is_operative(ifp
))
101 pim_if_addr_add_all(ifp
);
106 static int pim_zebra_if_del(int command
, struct zclient
*zclient
,
109 struct interface
*ifp
;
112 zebra api adds/dels interfaces using the same call
113 interface_add_read below, see comments in lib/zclient.c
115 comments in lib/zclient.c seem to indicate that calling
116 zebra_interface_add_read is the correct call, but that
117 results in an attemted out of bounds read which causes
118 pimd to assert. Other clients use zebra_interface_state_read
119 and it appears to work just fine.
121 ifp
= zebra_interface_state_read(zclient
->ibuf
);
125 if (PIM_DEBUG_ZEBRA
) {
126 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
128 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
129 ifp
->mtu
, if_is_operative(ifp
));
132 if (!if_is_operative(ifp
))
133 pim_if_addr_del_all(ifp
);
138 static int pim_zebra_if_state_up(int command
, struct zclient
*zclient
,
141 struct interface
*ifp
;
144 zebra api notifies interface up/down events by using the same call
145 zebra_interface_state_read below, see comments in lib/zclient.c
147 ifp
= zebra_interface_state_read(zclient
->ibuf
);
151 zlog_info("INTERFACE UP: %s ifindex=%d", ifp
->name
, ifp
->ifindex
);
153 if (PIM_DEBUG_ZEBRA
) {
154 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
156 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
157 ifp
->mtu
, if_is_operative(ifp
));
160 if (if_is_operative(ifp
)) {
162 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
164 pim_if_addr_add_all(ifp
);
170 static int pim_zebra_if_state_down(int command
, struct zclient
*zclient
,
173 struct interface
*ifp
;
176 zebra api notifies interface up/down events by using the same call
177 zebra_interface_state_read below, see comments in lib/zclient.c
179 ifp
= zebra_interface_state_read(zclient
->ibuf
);
183 zlog_info("INTERFACE DOWN: %s ifindex=%d", ifp
->name
, ifp
->ifindex
);
185 if (PIM_DEBUG_ZEBRA
) {
186 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
188 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
189 ifp
->mtu
, if_is_operative(ifp
));
192 if (!if_is_operative(ifp
)) {
194 pim_if_addr_del_all() suffices for shutting down IGMP,
195 but not for shutting down PIM
197 pim_if_addr_del_all(ifp
);
200 pim_sock_delete() closes the socket, stops read and timer threads,
201 and kills all neighbors.
204 pim_sock_delete(ifp
, "link down");
211 #ifdef PIM_DEBUG_IFADDR_DUMP
212 static void dump_if_address(struct interface
*ifp
)
214 struct connected
*ifc
;
215 struct listnode
*node
;
217 zlog_debug("%s %s: interface %s addresses:",
218 __FILE__
, __PRETTY_FUNCTION__
,
221 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
222 struct prefix
*p
= ifc
->address
;
224 if (p
->family
!= AF_INET
)
227 zlog_debug("%s %s: interface %s address %s %s",
228 __FILE__
, __PRETTY_FUNCTION__
,
230 inet_ntoa(p
->u
.prefix4
),
231 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
232 "secondary" : "primary");
237 static int pim_zebra_if_address_add(int command
, struct zclient
*zclient
,
243 zassert(command
== ZEBRA_INTERFACE_ADDRESS_ADD
);
246 zebra api notifies address adds/dels events by using the same call
247 interface_add_read below, see comments in lib/zclient.c
249 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
250 will add address to interface list by calling
251 connected_add_by_prefix()
253 c
= zebra_interface_address_read(command
, zclient
->ibuf
);
258 if (p
->family
!= AF_INET
)
261 if (PIM_DEBUG_ZEBRA
) {
263 prefix2str(p
, buf
, BUFSIZ
);
264 zlog_debug("%s: %s connected IP address %s flags %u %s",
266 c
->ifp
->name
, buf
, c
->flags
,
267 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
269 #ifdef PIM_DEBUG_IFADDR_DUMP
270 dump_if_address(c
->ifp
);
274 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
275 /* trying to add primary address */
277 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
278 if (primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
279 /* but we had a primary address already */
284 prefix2str(p
, buf
, BUFSIZ
);
285 pim_inet4_dump("<old?>", primary_addr
, old
, sizeof(old
));
287 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
289 c
->ifp
->name
, old
, buf
);
290 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
299 static int pim_zebra_if_address_del(int command
, struct zclient
*client
,
305 zassert(command
== ZEBRA_INTERFACE_ADDRESS_DELETE
);
308 zebra api notifies address adds/dels events by using the same call
309 interface_add_read below, see comments in lib/zclient.c
311 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
312 will remove address from interface list by calling
313 connected_delete_by_prefix()
315 c
= zebra_interface_address_read(command
, client
->ibuf
);
320 if (p
->family
!= AF_INET
)
323 if (PIM_DEBUG_ZEBRA
) {
325 prefix2str(p
, buf
, BUFSIZ
);
326 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
328 c
->ifp
->name
, buf
, c
->flags
,
329 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
331 #ifdef PIM_DEBUG_IFADDR_DUMP
332 dump_if_address(c
->ifp
);
336 pim_if_addr_del(c
, 0);
341 static void scan_upstream_rpf_cache()
343 struct listnode
*up_node
;
344 struct listnode
*up_nextnode
;
345 struct pim_upstream
*up
;
347 for (ALL_LIST_ELEMENTS(qpim_upstream_list
, up_node
, up_nextnode
, up
)) {
348 struct in_addr old_rpf_addr
;
349 enum pim_rpf_result rpf_result
;
351 rpf_result
= pim_rpf_update(up
, &old_rpf_addr
);
352 if (rpf_result
== PIM_RPF_FAILURE
)
355 if (rpf_result
== PIM_RPF_CHANGED
) {
357 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
360 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
362 Transitions from Joined State
364 RPF'(S,G) changes not due to an Assert
366 The upstream (S,G) state machine remains in Joined
367 state. Send Join(S,G) to the new upstream neighbor, which is
368 the new value of RPF'(S,G). Send Prune(S,G) to the old
369 upstream neighbor, which is the old value of RPF'(S,G). Set
370 the Join Timer (JT) to expire after t_periodic seconds.
374 /* send Prune(S,G) to the old upstream neighbor */
375 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
381 /* send Join(S,G) to the current upstream neighbor */
382 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
388 pim_upstream_join_timer_restart(up
);
389 } /* up->join_state == PIM_UPSTREAM_JOINED */
391 /* FIXME can join_desired actually be changed by pim_rpf_update()
392 returning PIM_RPF_CHANGED ? */
393 pim_upstream_update_join_desired(up
);
395 } /* PIM_RPF_CHANGED */
397 } /* for (qpim_upstream_list) */
403 struct listnode
*node
;
404 struct listnode
*nextnode
;
405 struct channel_oil
*c_oil
;
407 qpim_scan_oil_last
= pim_time_monotonic_sec();
408 ++qpim_scan_oil_events
;
410 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list
, node
, nextnode
, c_oil
)) {
412 int input_iface_vif_index
= fib_lookup_if_vif_index(c_oil
->oil
.mfcc_origin
);
413 if (input_iface_vif_index
< 1) {
414 char source_str
[100];
416 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
417 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
418 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
419 __FILE__
, __PRETTY_FUNCTION__
,
420 source_str
, group_str
);
424 if (input_iface_vif_index
== c_oil
->oil
.mfcc_parent
) {
429 if (PIM_DEBUG_ZEBRA
) {
430 struct interface
*old_iif
= pim_if_find_by_vif_index(c_oil
->oil
.mfcc_parent
);
431 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
432 char source_str
[100];
434 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
435 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
436 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
437 __FILE__
, __PRETTY_FUNCTION__
,
438 source_str
, group_str
,
439 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
440 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
443 /* new iif loops to existing oif ? */
444 if (c_oil
->oil
.mfcc_ttls
[input_iface_vif_index
]) {
445 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
447 if (PIM_DEBUG_ZEBRA
) {
448 char source_str
[100];
450 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
451 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
452 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
453 __FILE__
, __PRETTY_FUNCTION__
,
454 source_str
, group_str
,
455 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
458 del_oif(c_oil
, new_iif
, PIM_OIF_FLAG_PROTO_ANY
);
461 /* update iif vif_index */
462 old_vif_index
= c_oil
->oil
.mfcc_parent
;
463 c_oil
->oil
.mfcc_parent
= input_iface_vif_index
;
465 /* update kernel multicast forwarding cache (MFC) */
466 if (pim_mroute_add(&c_oil
->oil
)) {
467 /* just log warning */
468 struct interface
*old_iif
= pim_if_find_by_vif_index(old_vif_index
);
469 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
470 char source_str
[100];
472 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
473 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
474 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
475 __FILE__
, __PRETTY_FUNCTION__
,
476 source_str
, group_str
,
477 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
478 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
482 } /* for (qpim_channel_oil_list) */
485 static int on_rpf_cache_refresh(struct thread
*t
)
488 zassert(qpim_rpf_cache_refresher
);
490 qpim_rpf_cache_refresher
= 0;
492 /* update PIM protocol state */
493 scan_upstream_rpf_cache();
495 /* update kernel multicast forwarding cache (MFC) */
498 qpim_rpf_cache_refresh_last
= pim_time_monotonic_sec();
499 ++qpim_rpf_cache_refresh_events
;
504 static void sched_rpf_cache_refresh()
506 ++qpim_rpf_cache_refresh_requests
;
508 if (qpim_rpf_cache_refresher
) {
509 /* Refresh timer is already running */
513 /* Start refresh timer */
515 if (PIM_DEBUG_ZEBRA
) {
516 zlog_debug("%s: triggering %ld msec timer",
518 qpim_rpf_cache_refresh_delay_msec
);
521 THREAD_TIMER_MSEC_ON(master
, qpim_rpf_cache_refresher
,
522 on_rpf_cache_refresh
,
523 0, qpim_rpf_cache_refresh_delay_msec
);
526 static int redist_read_ipv4_route(int command
, struct zclient
*zclient
,
530 struct zapi_ipv4 api
;
531 unsigned long ifindex
;
532 struct in_addr nexthop
;
533 struct prefix_ipv4 p
;
536 if (length
< min_len
) {
537 zlog_warn("%s %s: short buffer: length=%d min=%d",
538 __FILE__
, __PRETTY_FUNCTION__
,
547 /* Type, flags, message. */
548 api
.type
= stream_getc(s
);
549 api
.flags
= stream_getc(s
);
550 api
.message
= stream_getc(s
);
552 /* IPv4 prefix length. */
553 memset(&p
, 0, sizeof(struct prefix_ipv4
));
555 p
.prefixlen
= stream_getc(s
);
559 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? 5 : 0 +
560 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? 5 : 0 +
561 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? 1 : 0 +
562 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? 4 : 0;
564 if (PIM_DEBUG_ZEBRA
) {
565 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
566 __FILE__
, __PRETTY_FUNCTION__
,
568 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
569 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
570 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
571 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
574 if (length
< min_len
) {
575 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
576 __FILE__
, __PRETTY_FUNCTION__
,
578 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
579 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
580 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
581 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
586 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
588 /* Nexthop, ifindex, distance, metric. */
589 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
590 api
.nexthop_num
= stream_getc(s
);
591 nexthop
.s_addr
= stream_get_ipv4(s
);
593 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
)) {
594 api
.ifindex_num
= stream_getc(s
);
595 ifindex
= stream_getl(s
);
598 api
.distance
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ?
602 api
.metric
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ?
607 case ZEBRA_IPV4_ROUTE_ADD
:
608 if (PIM_DEBUG_ZEBRA
) {
609 char buf
[2][INET_ADDRSTRLEN
];
610 zlog_debug("%s: add %s %s/%d "
611 "nexthop %s ifindex %ld metric%s %u distance%s %u",
613 zebra_route_string(api
.type
),
614 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
616 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
618 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
620 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
624 case ZEBRA_IPV4_ROUTE_DELETE
:
625 if (PIM_DEBUG_ZEBRA
) {
626 char buf
[2][INET_ADDRSTRLEN
];
627 zlog_debug("%s: delete %s %s/%d "
628 "nexthop %s ifindex %ld metric%s %u distance%s %u",
630 zebra_route_string(api
.type
),
631 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
633 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
635 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
637 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
642 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__
, command
);
646 sched_rpf_cache_refresh();
651 void pim_zebra_init(char *zebra_sock_path
)
656 zclient_serv_path_set(zebra_sock_path
);
658 #ifdef HAVE_TCP_ZEBRA
659 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT
);
661 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
664 /* Socket for receiving updates from Zebra daemon */
665 qpim_zclient_update
= zclient_new();
667 qpim_zclient_update
->router_id_update
= pim_router_id_update_zebra
;
668 qpim_zclient_update
->interface_add
= pim_zebra_if_add
;
669 qpim_zclient_update
->interface_delete
= pim_zebra_if_del
;
670 qpim_zclient_update
->interface_up
= pim_zebra_if_state_up
;
671 qpim_zclient_update
->interface_down
= pim_zebra_if_state_down
;
672 qpim_zclient_update
->interface_address_add
= pim_zebra_if_address_add
;
673 qpim_zclient_update
->interface_address_delete
= pim_zebra_if_address_del
;
674 qpim_zclient_update
->ipv4_route_add
= redist_read_ipv4_route
;
675 qpim_zclient_update
->ipv4_route_delete
= redist_read_ipv4_route
;
677 zclient_init(qpim_zclient_update
, ZEBRA_ROUTE_PIM
);
678 if (PIM_DEBUG_PIM_TRACE
) {
679 zlog_info("zclient_init cleared redistribution request");
682 zassert(qpim_zclient_update
->redist_default
== ZEBRA_ROUTE_PIM
);
684 /* Request all redistribution */
685 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
686 if (i
== qpim_zclient_update
->redist_default
)
688 qpim_zclient_update
->redist
[i
] = 1;
689 if (PIM_DEBUG_PIM_TRACE
) {
690 zlog_debug("%s: requesting redistribution for %s (%i)",
691 __PRETTY_FUNCTION__
, zebra_route_string(i
), i
);
695 /* Request default information */
696 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
697 qpim_zclient_update
, VRF_DEFAULT
);
699 if (PIM_DEBUG_PIM_TRACE
) {
700 zlog_info("%s: requesting default information redistribution",
701 __PRETTY_FUNCTION__
);
703 zlog_notice("%s: zclient update socket initialized",
704 __PRETTY_FUNCTION__
);
707 zassert(!qpim_zclient_lookup
);
708 qpim_zclient_lookup
= zclient_lookup_new();
709 zassert(qpim_zclient_lookup
);
712 void igmp_anysource_forward_start(struct igmp_group
*group
)
714 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
715 zassert(group
->group_filtermode_isexcl
);
716 zassert(listcount(group
->group_source_list
) < 1);
718 if (PIM_DEBUG_IGMP_TRACE
) {
719 zlog_debug("%s %s: UNIMPLEMENTED",
720 __FILE__
, __PRETTY_FUNCTION__
);
724 void igmp_anysource_forward_stop(struct igmp_group
*group
)
726 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
727 zassert((!group
->group_filtermode_isexcl
) || (listcount(group
->group_source_list
) > 0));
729 if (PIM_DEBUG_IGMP_TRACE
) {
730 zlog_debug("%s %s: UNIMPLEMENTED",
731 __FILE__
, __PRETTY_FUNCTION__
);
735 static int fib_lookup_if_vif_index(struct in_addr addr
)
737 struct pim_zlookup_nexthop nexthop_tab
[PIM_NEXTHOP_IFINDEX_TAB_SIZE
];
742 num_ifindex
= zclient_lookup_nexthop(qpim_zclient_lookup
, nexthop_tab
,
743 PIM_NEXTHOP_IFINDEX_TAB_SIZE
, addr
,
744 PIM_NEXTHOP_LOOKUP_MAX
);
745 if (num_ifindex
< 1) {
747 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
748 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
749 __FILE__
, __PRETTY_FUNCTION__
,
754 first_ifindex
= nexthop_tab
[0].ifindex
;
756 if (num_ifindex
> 1) {
758 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
759 zlog_debug("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
760 __FILE__
, __PRETTY_FUNCTION__
,
761 num_ifindex
, addr_str
, first_ifindex
);
762 /* debug warning only, do not return */
765 if (PIM_DEBUG_ZEBRA
) {
767 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
768 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
769 __FILE__
, __PRETTY_FUNCTION__
,
770 first_ifindex
, ifindex2ifname(first_ifindex
), addr_str
);
773 vif_index
= pim_if_find_vifindex_by_ifindex(first_ifindex
);
777 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
778 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
779 __FILE__
, __PRETTY_FUNCTION__
,
780 vif_index
, addr_str
);
784 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
786 if (vif_index
> qpim_mroute_oif_highest_vif_index
) {
788 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
789 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
790 __FILE__
, __PRETTY_FUNCTION__
,
791 vif_index
, qpim_mroute_oif_highest_vif_index
, addr_str
);
793 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
794 __FILE__
, __PRETTY_FUNCTION__
,
795 ifindex2ifname(vif_index
),
804 static int add_oif(struct channel_oil
*channel_oil
,
805 struct interface
*oif
,
808 struct pim_interface
*pim_ifp
;
811 zassert(channel_oil
);
815 if (PIM_DEBUG_MROUTE
) {
817 char source_str
[100];
818 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
819 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
820 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
821 __FILE__
, __PRETTY_FUNCTION__
,
822 source_str
, group_str
,
823 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
826 if (pim_ifp
->mroute_vif_index
< 1) {
827 zlog_warn("%s %s: interface %s vif_index=%d < 1",
828 __FILE__
, __PRETTY_FUNCTION__
,
829 oif
->name
, pim_ifp
->mroute_vif_index
);
833 #ifdef PIM_ENFORCE_LOOPFREE_MFC
835 Prevent creating MFC entry with OIF=IIF.
837 This is a protection against implementation mistakes.
839 PIM protocol implicitely ensures loopfree multicast topology.
841 IGMP must be protected against adding looped MFC entries created
842 by both source and receiver attached to the same interface. See
845 if (pim_ifp
->mroute_vif_index
== channel_oil
->oil
.mfcc_parent
) {
847 char source_str
[100];
848 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
849 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
850 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
851 __FILE__
, __PRETTY_FUNCTION__
,
852 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
853 source_str
, group_str
);
858 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
859 zassert(pim_ifp
->mroute_vif_index
<= qpim_mroute_oif_highest_vif_index
);
861 /* Prevent single protocol from subscribing same interface to
862 channel (S,G) multiple times */
863 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & proto_mask
) {
865 char source_str
[100];
866 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
867 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
868 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
869 __FILE__
, __PRETTY_FUNCTION__
,
870 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
871 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
872 source_str
, group_str
);
876 /* Allow other protocol to request subscription of same interface to
877 channel (S,G) multiple times, by silently ignoring further
879 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
881 /* Check the OIF really exists before returning, and only log
883 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
885 char source_str
[100];
886 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
887 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
888 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
889 __FILE__
, __PRETTY_FUNCTION__
,
890 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
891 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
892 source_str
, group_str
);
898 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
902 char source_str
[100];
903 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
904 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
905 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
906 __FILE__
, __PRETTY_FUNCTION__
,
907 oif
->name
, pim_ifp
->mroute_vif_index
,
908 source_str
, group_str
);
912 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = PIM_MROUTE_MIN_TTL
;
914 if (pim_mroute_add(&channel_oil
->oil
)) {
916 char source_str
[100];
917 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
918 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
919 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
920 __FILE__
, __PRETTY_FUNCTION__
,
921 oif
->name
, pim_ifp
->mroute_vif_index
,
922 source_str
, group_str
);
924 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
928 channel_oil
->oif_creation
[pim_ifp
->mroute_vif_index
] = pim_time_monotonic_sec();
929 ++channel_oil
->oil_size
;
930 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] |= proto_mask
;
932 if (PIM_DEBUG_MROUTE
) {
934 char source_str
[100];
935 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
936 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
937 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
938 __FILE__
, __PRETTY_FUNCTION__
,
939 source_str
, group_str
,
940 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
946 static int del_oif(struct channel_oil
*channel_oil
,
947 struct interface
*oif
,
950 struct pim_interface
*pim_ifp
;
953 zassert(channel_oil
);
957 zassert(pim_ifp
->mroute_vif_index
>= 1);
958 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
959 zassert(pim_ifp
->mroute_vif_index
<= qpim_mroute_oif_highest_vif_index
);
961 if (PIM_DEBUG_MROUTE
) {
963 char source_str
[100];
964 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
965 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
966 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
967 __FILE__
, __PRETTY_FUNCTION__
,
968 source_str
, group_str
,
969 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
972 /* Prevent single protocol from unsubscribing same interface from
973 channel (S,G) multiple times */
974 if (!(channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & proto_mask
)) {
976 char source_str
[100];
977 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
978 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
979 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
980 __FILE__
, __PRETTY_FUNCTION__
,
981 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
982 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
983 source_str
, group_str
);
987 /* Mark that protocol is no longer interested in this OIF */
988 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] &= ~proto_mask
;
990 /* Allow multiple protocols to unsubscribe same interface from
991 channel (S,G) multiple times, by silently ignoring requests while
992 there is at least one protocol interested in the channel */
993 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
995 /* Check the OIF keeps existing before returning, and only log
997 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
999 char source_str
[100];
1000 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
1001 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
1002 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
1003 __FILE__
, __PRETTY_FUNCTION__
,
1004 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
1005 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
1006 source_str
, group_str
);
1012 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
1015 char group_str
[100];
1016 char source_str
[100];
1017 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
1018 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
1019 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1020 __FILE__
, __PRETTY_FUNCTION__
,
1021 oif
->name
, pim_ifp
->mroute_vif_index
,
1022 source_str
, group_str
);
1026 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = 0;
1028 if (pim_mroute_add(&channel_oil
->oil
)) {
1029 char group_str
[100];
1030 char source_str
[100];
1031 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
1032 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
1033 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1034 __FILE__
, __PRETTY_FUNCTION__
,
1035 oif
->name
, pim_ifp
->mroute_vif_index
,
1036 source_str
, group_str
);
1038 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
1042 --channel_oil
->oil_size
;
1044 if (channel_oil
->oil_size
< 1) {
1045 if (pim_mroute_del(&channel_oil
->oil
)) {
1046 /* just log a warning in case of failure */
1047 char group_str
[100];
1048 char source_str
[100];
1049 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
1050 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
1051 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1052 __FILE__
, __PRETTY_FUNCTION__
,
1053 source_str
, group_str
);
1057 if (PIM_DEBUG_MROUTE
) {
1058 char group_str
[100];
1059 char source_str
[100];
1060 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
1061 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
1062 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1063 __FILE__
, __PRETTY_FUNCTION__
,
1064 source_str
, group_str
,
1065 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
1071 void igmp_source_forward_start(struct igmp_source
*source
)
1073 struct igmp_group
*group
;
1076 if (PIM_DEBUG_IGMP_TRACE
) {
1077 char source_str
[100];
1078 char group_str
[100];
1079 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1080 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1081 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1082 __PRETTY_FUNCTION__
,
1083 source_str
, group_str
,
1084 source
->source_group
->group_igmp_sock
->fd
,
1085 source
->source_group
->group_igmp_sock
->interface
->name
,
1086 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1089 /* Prevent IGMP interface from installing multicast route multiple
1091 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1095 group
= source
->source_group
;
1097 if (!source
->source_channel_oil
) {
1098 struct pim_interface
*pim_oif
;
1099 int input_iface_vif_index
= fib_lookup_if_vif_index(source
->source_addr
);
1100 if (input_iface_vif_index
< 1) {
1101 char source_str
[100];
1102 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1103 zlog_warn("%s %s: could not find input interface for source %s",
1104 __FILE__
, __PRETTY_FUNCTION__
,
1110 Protect IGMP against adding looped MFC entries created by both
1111 source and receiver attached to the same interface. See TODO
1114 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
1116 zlog_warn("%s: multicast not enabled on oif=%s ?",
1117 __PRETTY_FUNCTION__
,
1118 source
->source_group
->group_igmp_sock
->interface
->name
);
1121 if (pim_oif
->mroute_vif_index
< 1) {
1122 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1123 __FILE__
, __PRETTY_FUNCTION__
,
1124 source
->source_group
->group_igmp_sock
->interface
->name
,
1125 pim_oif
->mroute_vif_index
);
1128 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
1129 /* ignore request for looped MFC entry */
1130 if (PIM_DEBUG_IGMP_TRACE
) {
1131 char source_str
[100];
1132 char group_str
[100];
1133 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1134 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1135 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1136 __PRETTY_FUNCTION__
,
1137 source_str
, group_str
,
1138 source
->source_group
->group_igmp_sock
->fd
,
1139 source
->source_group
->group_igmp_sock
->interface
->name
,
1140 input_iface_vif_index
);
1145 source
->source_channel_oil
= pim_channel_oil_add(group
->group_addr
,
1146 source
->source_addr
,
1147 input_iface_vif_index
);
1148 if (!source
->source_channel_oil
) {
1149 char group_str
[100];
1150 char source_str
[100];
1151 pim_inet4_dump("<group?>", group
->group_addr
, group_str
, sizeof(group_str
));
1152 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1153 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1154 __FILE__
, __PRETTY_FUNCTION__
,
1155 source_str
, group_str
);
1160 result
= add_oif(source
->source_channel_oil
,
1161 group
->group_igmp_sock
->interface
,
1162 PIM_OIF_FLAG_PROTO_IGMP
);
1164 zlog_warn("%s: add_oif() failed with return=%d",
1170 Feed IGMPv3-gathered local membership information into PIM
1171 per-interface (S,G) state.
1173 pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
,
1174 source
->source_addr
, group
->group_addr
);
1176 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1180 igmp_source_forward_stop: stop fowarding, but keep the source
1181 igmp_source_delete: stop fowarding, and delete the source
1183 void igmp_source_forward_stop(struct igmp_source
*source
)
1185 struct igmp_group
*group
;
1188 if (PIM_DEBUG_IGMP_TRACE
) {
1189 char source_str
[100];
1190 char group_str
[100];
1191 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1192 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1193 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1194 __PRETTY_FUNCTION__
,
1195 source_str
, group_str
,
1196 source
->source_group
->group_igmp_sock
->fd
,
1197 source
->source_group
->group_igmp_sock
->interface
->name
,
1198 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1201 /* Prevent IGMP interface from removing multicast route multiple
1203 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1207 group
= source
->source_group
;
1210 It appears that in certain circumstances that
1211 igmp_source_forward_stop is called when IGMP forwarding
1212 was not enabled in oif_flags for this outgoing interface.
1213 Possibly because of multiple calls. When that happens, we
1214 enter the below if statement and this function returns early
1215 which in turn triggers the calling function to assert.
1216 Making the call to del_oif and ignoring the return code
1217 fixes the issue without ill effect, similar to
1218 pim_forward_stop below.
1220 result
= del_oif(source
->source_channel_oil
,
1221 group
->group_igmp_sock
->interface
,
1222 PIM_OIF_FLAG_PROTO_IGMP
);
1224 zlog_warn("%s: del_oif() failed with return=%d",
1230 Feed IGMPv3-gathered local membership information into PIM
1231 per-interface (S,G) state.
1233 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1234 source
->source_addr
, group
->group_addr
);
1236 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1239 void pim_forward_start(struct pim_ifchannel
*ch
)
1241 struct pim_upstream
*up
= ch
->upstream
;
1243 if (PIM_DEBUG_PIM_TRACE
) {
1244 char source_str
[100];
1245 char group_str
[100];
1246 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1247 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1248 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1249 __PRETTY_FUNCTION__
,
1250 source_str
, group_str
, ch
->interface
->name
);
1253 if (!up
->channel_oil
) {
1254 int input_iface_vif_index
= fib_lookup_if_vif_index(up
->source_addr
);
1255 if (input_iface_vif_index
< 1) {
1256 char source_str
[100];
1257 pim_inet4_dump("<source?>", up
->source_addr
, source_str
, sizeof(source_str
));
1258 zlog_warn("%s %s: could not find input interface for source %s",
1259 __FILE__
, __PRETTY_FUNCTION__
,
1264 up
->channel_oil
= pim_channel_oil_add(up
->group_addr
, up
->source_addr
,
1265 input_iface_vif_index
);
1266 if (!up
->channel_oil
) {
1267 char group_str
[100];
1268 char source_str
[100];
1269 pim_inet4_dump("<group?>", up
->group_addr
, group_str
, sizeof(group_str
));
1270 pim_inet4_dump("<source?>", up
->source_addr
, source_str
, sizeof(source_str
));
1271 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1272 __FILE__
, __PRETTY_FUNCTION__
,
1273 source_str
, group_str
);
1278 add_oif(up
->channel_oil
,
1280 PIM_OIF_FLAG_PROTO_PIM
);
1283 void pim_forward_stop(struct pim_ifchannel
*ch
)
1285 struct pim_upstream
*up
= ch
->upstream
;
1287 if (PIM_DEBUG_PIM_TRACE
) {
1288 char source_str
[100];
1289 char group_str
[100];
1290 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1291 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1292 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1293 __PRETTY_FUNCTION__
,
1294 source_str
, group_str
, ch
->interface
->name
);
1297 if (!up
->channel_oil
) {
1298 char source_str
[100];
1299 char group_str
[100];
1300 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1301 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1302 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1303 __PRETTY_FUNCTION__
,
1304 source_str
, group_str
, ch
->interface
->name
);
1309 del_oif(up
->channel_oil
,
1311 PIM_OIF_FLAG_PROTO_PIM
);