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 #include "pim_igmpv3.h"
48 #undef PIM_DEBUG_IFADDR_DUMP
49 #define PIM_DEBUG_IFADDR_DUMP
51 static int fib_lookup_if_vif_index(struct in_addr addr
);
52 static int del_oif(struct channel_oil
*channel_oil
,
53 struct interface
*oif
,
56 /* Router-id update message from zebra. */
57 static int pim_router_id_update_zebra(int command
, struct zclient
*zclient
,
58 zebra_size_t length
, vrf_id_t vrf_id
)
60 struct prefix router_id
;
62 zebra_router_id_update_read(zclient
->ibuf
, &router_id
);
67 static int pim_zebra_if_add(int command
, struct zclient
*zclient
,
68 zebra_size_t length
, vrf_id_t vrf_id
)
70 struct interface
*ifp
;
73 zebra api adds/dels interfaces using the same call
74 interface_add_read below, see comments in lib/zclient.c
76 ifp
= zebra_interface_add_read(zclient
->ibuf
, vrf_id
);
80 if (PIM_DEBUG_ZEBRA
) {
81 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
83 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
84 ifp
->mtu
, if_is_operative(ifp
));
87 if (if_is_operative(ifp
))
88 pim_if_addr_add_all(ifp
);
93 static int pim_zebra_if_del(int command
, struct zclient
*zclient
,
94 zebra_size_t length
, vrf_id_t vrf_id
)
96 struct interface
*ifp
;
99 zebra api adds/dels interfaces using the same call
100 interface_add_read below, see comments in lib/zclient.c
102 comments in lib/zclient.c seem to indicate that calling
103 zebra_interface_add_read is the correct call, but that
104 results in an attemted out of bounds read which causes
105 pimd to assert. Other clients use zebra_interface_state_read
106 and it appears to work just fine.
108 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
112 if (PIM_DEBUG_ZEBRA
) {
113 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
115 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
116 ifp
->mtu
, if_is_operative(ifp
));
119 if (!if_is_operative(ifp
))
120 pim_if_addr_del_all(ifp
);
125 static int pim_zebra_if_state_up(int command
, struct zclient
*zclient
,
126 zebra_size_t length
, vrf_id_t vrf_id
)
128 struct interface
*ifp
;
131 zebra api notifies interface up/down events by using the same call
132 zebra_interface_state_read below, see comments in lib/zclient.c
134 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
138 if (PIM_DEBUG_ZEBRA
) {
139 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
141 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
142 ifp
->mtu
, if_is_operative(ifp
));
145 if (if_is_operative(ifp
)) {
147 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
149 pim_if_addr_add_all(ifp
);
155 static int pim_zebra_if_state_down(int command
, struct zclient
*zclient
,
156 zebra_size_t length
, vrf_id_t vrf_id
)
158 struct interface
*ifp
;
161 zebra api notifies interface up/down events by using the same call
162 zebra_interface_state_read below, see comments in lib/zclient.c
164 ifp
= zebra_interface_state_read(zclient
->ibuf
, vrf_id
);
168 if (PIM_DEBUG_ZEBRA
) {
169 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
171 ifp
->name
, ifp
->ifindex
, (long)ifp
->flags
, ifp
->metric
,
172 ifp
->mtu
, if_is_operative(ifp
));
175 if (!if_is_operative(ifp
)) {
177 pim_if_addr_del_all() suffices for shutting down IGMP,
178 but not for shutting down PIM
180 pim_if_addr_del_all(ifp
);
183 pim_sock_delete() closes the socket, stops read and timer threads,
184 and kills all neighbors.
187 pim_sock_delete(ifp
, "link down");
194 #ifdef PIM_DEBUG_IFADDR_DUMP
195 static void dump_if_address(struct interface
*ifp
)
197 struct connected
*ifc
;
198 struct listnode
*node
;
200 zlog_debug("%s %s: interface %s addresses:",
201 __FILE__
, __PRETTY_FUNCTION__
,
204 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
205 struct prefix
*p
= ifc
->address
;
207 if (p
->family
!= AF_INET
)
210 zlog_debug("%s %s: interface %s address %s %s",
211 __FILE__
, __PRETTY_FUNCTION__
,
213 inet_ntoa(p
->u
.prefix4
),
214 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
215 "secondary" : "primary");
220 static int pim_zebra_if_address_add(int command
, struct zclient
*zclient
,
221 zebra_size_t length
, vrf_id_t vrf_id
)
225 struct in_addr old
= { .s_addr
= 0 };
228 zebra api notifies address adds/dels events by using the same call
229 interface_add_read below, see comments in lib/zclient.c
231 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
232 will add address to interface list by calling
233 connected_add_by_prefix()
235 c
= zebra_interface_address_read(command
, zclient
->ibuf
, vrf_id
);
240 if (p
->family
!= AF_INET
)
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 pim_rp_check_rp (old
, p
->u
.prefix4
);
258 if (!CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
)) {
259 /* trying to add primary address */
261 struct in_addr primary_addr
= pim_find_primary_addr(c
->ifp
);
262 if (primary_addr
.s_addr
!= p
->u
.prefix4
.s_addr
) {
263 if (PIM_DEBUG_ZEBRA
) {
264 /* but we had a primary address already */
269 prefix2str(p
, buf
, BUFSIZ
);
270 pim_inet4_dump("<old?>", primary_addr
, old
, sizeof(old
));
272 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
274 c
->ifp
->name
, old
, buf
);
276 SET_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
);
285 static int pim_zebra_if_address_del(int command
, struct zclient
*client
,
286 zebra_size_t length
, vrf_id_t vrf_id
)
290 struct in_addr
new = { .s_addr
= 0 };
293 zebra api notifies address adds/dels events by using the same call
294 interface_add_read below, see comments in lib/zclient.c
296 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
297 will remove address from interface list by calling
298 connected_delete_by_prefix()
300 c
= zebra_interface_address_read(command
, client
->ibuf
, vrf_id
);
305 if (p
->family
!= AF_INET
)
308 if (PIM_DEBUG_ZEBRA
) {
310 prefix2str(p
, buf
, BUFSIZ
);
311 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
313 c
->ifp
->name
, buf
, c
->flags
,
314 CHECK_FLAG(c
->flags
, ZEBRA_IFA_SECONDARY
) ? "secondary" : "primary");
316 #ifdef PIM_DEBUG_IFADDR_DUMP
317 dump_if_address(c
->ifp
);
321 pim_rp_check_rp (p
->u
.prefix4
, new);
322 pim_if_addr_del(c
, 0);
327 static void scan_upstream_rpf_cache()
329 struct listnode
*up_node
;
330 struct listnode
*up_nextnode
;
331 struct pim_upstream
*up
;
333 for (ALL_LIST_ELEMENTS(qpim_upstream_list
, up_node
, up_nextnode
, up
)) {
334 struct in_addr old_rpf_addr
;
335 enum pim_rpf_result rpf_result
;
337 rpf_result
= pim_rpf_update(up
, &old_rpf_addr
, NULL
);
338 if (rpf_result
== PIM_RPF_FAILURE
)
341 if (rpf_result
== PIM_RPF_CHANGED
) {
343 if (up
->join_state
== PIM_UPSTREAM_JOINED
) {
346 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
348 Transitions from Joined State
350 RPF'(S,G) changes not due to an Assert
352 The upstream (S,G) state machine remains in Joined
353 state. Send Join(S,G) to the new upstream neighbor, which is
354 the new value of RPF'(S,G). Send Prune(S,G) to the old
355 upstream neighbor, which is the old value of RPF'(S,G). Set
356 the Join Timer (JT) to expire after t_periodic seconds.
360 /* send Prune(S,G) to the old upstream neighbor */
361 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
367 /* send Join(S,G) to the current upstream neighbor */
368 pim_joinprune_send(up
->rpf
.source_nexthop
.interface
,
374 pim_upstream_join_timer_restart(up
);
375 } /* up->join_state == PIM_UPSTREAM_JOINED */
377 /* FIXME can join_desired actually be changed by pim_rpf_update()
378 returning PIM_RPF_CHANGED ? */
379 pim_upstream_update_join_desired(up
);
381 } /* PIM_RPF_CHANGED */
383 } /* for (qpim_upstream_list) */
388 pim_scan_individual_oil (struct channel_oil
*c_oil
)
390 struct in_addr vif_source
;
391 int input_iface_vif_index
;
394 if (!pim_rp_set_upstream_addr (&vif_source
, c_oil
->oil
.mfcc_origin
))
397 input_iface_vif_index
= fib_lookup_if_vif_index (vif_source
);
398 if (input_iface_vif_index
< 1)
402 char source_str
[100];
404 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
405 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
406 zlog_debug("%s %s: could not find input interface(%d) for (S,G)=(%s,%s)",
407 __FILE__
, __PRETTY_FUNCTION__
, c_oil
->oil
.mfcc_parent
,
408 source_str
, group_str
);
410 pim_mroute_del (c_oil
);
414 if (input_iface_vif_index
== c_oil
->oil
.mfcc_parent
)
422 struct interface
*old_iif
= pim_if_find_by_vif_index(c_oil
->oil
.mfcc_parent
);
423 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
424 char source_str
[100];
426 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
427 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
428 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
429 __FILE__
, __PRETTY_FUNCTION__
,
430 source_str
, group_str
,
431 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
432 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
435 /* new iif loops to existing oif ? */
436 if (c_oil
->oil
.mfcc_ttls
[input_iface_vif_index
])
438 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
440 if (PIM_DEBUG_ZEBRA
) {
441 char source_str
[100];
443 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
444 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
445 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
446 __FILE__
, __PRETTY_FUNCTION__
,
447 source_str
, group_str
,
448 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
451 del_oif(c_oil
, new_iif
, PIM_OIF_FLAG_PROTO_ANY
);
454 /* update iif vif_index */
455 old_vif_index
= c_oil
->oil
.mfcc_parent
;
456 c_oil
->oil
.mfcc_parent
= input_iface_vif_index
;
459 /* update kernel multicast forwarding cache (MFC) */
460 if (pim_mroute_add(c_oil
))
462 /* just log warning */
463 struct interface
*old_iif
= pim_if_find_by_vif_index(old_vif_index
);
464 struct interface
*new_iif
= pim_if_find_by_vif_index(input_iface_vif_index
);
465 char source_str
[100];
467 pim_inet4_dump("<source?>", c_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
468 pim_inet4_dump("<group?>", c_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
469 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
470 __FILE__
, __PRETTY_FUNCTION__
,
471 source_str
, group_str
,
472 old_iif
? old_iif
->name
: "<old_iif?>", c_oil
->oil
.mfcc_parent
,
473 new_iif
? new_iif
->name
: "<new_iif?>", input_iface_vif_index
);
479 struct listnode
*node
;
480 struct listnode
*nextnode
;
481 struct channel_oil
*c_oil
;
483 qpim_scan_oil_last
= pim_time_monotonic_sec();
484 ++qpim_scan_oil_events
;
486 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list
, node
, nextnode
, c_oil
))
487 pim_scan_individual_oil (c_oil
);
490 static int on_rpf_cache_refresh(struct thread
*t
)
493 zassert(qpim_rpf_cache_refresher
);
495 qpim_rpf_cache_refresher
= 0;
497 /* update PIM protocol state */
498 scan_upstream_rpf_cache();
500 /* update kernel multicast forwarding cache (MFC) */
503 qpim_rpf_cache_refresh_last
= pim_time_monotonic_sec();
504 ++qpim_rpf_cache_refresh_events
;
509 static void sched_rpf_cache_refresh()
511 ++qpim_rpf_cache_refresh_requests
;
513 if (qpim_rpf_cache_refresher
) {
514 /* Refresh timer is already running */
518 /* Start refresh timer */
520 if (PIM_DEBUG_ZEBRA
) {
521 zlog_debug("%s: triggering %ld msec timer",
523 qpim_rpf_cache_refresh_delay_msec
);
526 THREAD_TIMER_MSEC_ON(master
, qpim_rpf_cache_refresher
,
527 on_rpf_cache_refresh
,
528 0, qpim_rpf_cache_refresh_delay_msec
);
531 static int redist_read_ipv4_route(int command
, struct zclient
*zclient
,
532 zebra_size_t length
, vrf_id_t vrf_id
)
535 struct zapi_ipv4 api
;
537 struct in_addr nexthop
;
538 struct prefix_ipv4 p
;
541 if (length
< min_len
) {
542 zlog_warn("%s %s: short buffer: length=%d min=%d",
543 __FILE__
, __PRETTY_FUNCTION__
,
552 /* Type, flags, message. */
553 api
.type
= stream_getc(s
);
554 api
.instance
= stream_getw (s
);
555 api
.flags
= stream_getl(s
);
556 api
.message
= stream_getc(s
);
558 /* IPv4 prefix length. */
559 memset(&p
, 0, sizeof(struct prefix_ipv4
));
561 p
.prefixlen
= stream_getc(s
);
565 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? 5 : 0 +
566 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? 5 : 0 +
567 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? 1 : 0 +
568 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? 4 : 0;
570 if (PIM_DEBUG_ZEBRA
) {
571 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
572 __FILE__
, __PRETTY_FUNCTION__
,
574 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
575 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
576 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
577 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
580 if (length
< min_len
) {
581 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
582 __FILE__
, __PRETTY_FUNCTION__
,
584 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
) ? "nh" : "",
585 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
) ? " ifi" : "",
586 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? " dist" : "",
587 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? " metr" : "");
592 stream_get(&p
.prefix
, s
, PSIZE(p
.prefixlen
));
594 /* Nexthop, ifindex, distance, metric. */
595 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_NEXTHOP
)) {
596 api
.nexthop_num
= stream_getc(s
);
597 nexthop
.s_addr
= stream_get_ipv4(s
);
599 if (CHECK_FLAG(api
.message
, ZAPI_MESSAGE_IFINDEX
)) {
600 api
.ifindex_num
= stream_getc(s
);
601 ifindex
= stream_getl(s
);
604 api
.distance
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ?
608 api
.metric
= CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ?
612 if (CHECK_FLAG (api
.message
, ZAPI_MESSAGE_TAG
))
613 api
.tag
= stream_getw (s
);
618 case ZEBRA_REDISTRIBUTE_IPV4_ADD
:
619 if (PIM_DEBUG_ZEBRA
) {
620 char buf
[2][INET_ADDRSTRLEN
];
621 zlog_debug("%s: add %s %s/%d "
622 "nexthop %s ifindex %d metric%s %u distance%s %u",
624 zebra_route_string(api
.type
),
625 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
627 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
629 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
631 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
635 case ZEBRA_REDISTRIBUTE_IPV4_DEL
:
636 if (PIM_DEBUG_ZEBRA
) {
637 char buf
[2][INET_ADDRSTRLEN
];
638 zlog_debug("%s: delete %s %s/%d "
639 "nexthop %s ifindex %d metric%s %u distance%s %u",
641 zebra_route_string(api
.type
),
642 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
644 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
646 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
648 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
653 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__
, command
);
657 sched_rpf_cache_refresh();
663 pim_zebra_connected (struct zclient
*zclient
)
665 zclient_send_reg_requests (zclient
, VRF_DEFAULT
);
667 void pim_zebra_init(char *zebra_sock_path
)
672 zclient_serv_path_set(zebra_sock_path
);
674 #ifdef HAVE_TCP_ZEBRA
675 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT
);
677 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
680 /* Socket for receiving updates from Zebra daemon */
681 qpim_zclient_update
= zclient_new (master
);
683 qpim_zclient_update
->zebra_connected
= pim_zebra_connected
;
684 qpim_zclient_update
->router_id_update
= pim_router_id_update_zebra
;
685 qpim_zclient_update
->interface_add
= pim_zebra_if_add
;
686 qpim_zclient_update
->interface_delete
= pim_zebra_if_del
;
687 qpim_zclient_update
->interface_up
= pim_zebra_if_state_up
;
688 qpim_zclient_update
->interface_down
= pim_zebra_if_state_down
;
689 qpim_zclient_update
->interface_address_add
= pim_zebra_if_address_add
;
690 qpim_zclient_update
->interface_address_delete
= pim_zebra_if_address_del
;
691 qpim_zclient_update
->redistribute_route_ipv4_add
= redist_read_ipv4_route
;
692 qpim_zclient_update
->redistribute_route_ipv4_del
= redist_read_ipv4_route
;
694 zclient_init(qpim_zclient_update
, ZEBRA_ROUTE_PIM
, 0);
695 if (PIM_DEBUG_PIM_TRACE
) {
696 zlog_info("zclient_init cleared redistribution request");
699 zassert(qpim_zclient_update
->redist_default
== ZEBRA_ROUTE_PIM
);
701 /* Request all redistribution */
702 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
703 if (i
== qpim_zclient_update
->redist_default
)
705 vrf_bitmap_set (qpim_zclient_update
->redist
[AFI_IP
][i
], VRF_DEFAULT
);;
706 if (PIM_DEBUG_PIM_TRACE
) {
707 zlog_debug("%s: requesting redistribution for %s (%i)",
708 __PRETTY_FUNCTION__
, zebra_route_string(i
), i
);
712 /* Request default information */
713 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
714 qpim_zclient_update
, VRF_DEFAULT
);
716 if (PIM_DEBUG_PIM_TRACE
) {
717 zlog_info("%s: requesting default information redistribution",
718 __PRETTY_FUNCTION__
);
720 zlog_notice("%s: zclient update socket initialized",
721 __PRETTY_FUNCTION__
);
724 zassert(!qpim_zclient_lookup
);
725 qpim_zclient_lookup
= zclient_lookup_new();
726 zassert(qpim_zclient_lookup
);
729 void igmp_anysource_forward_start(struct igmp_group
*group
)
731 struct igmp_source
*source
;
732 struct in_addr src_addr
= { .s_addr
= 0 };
733 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
734 zassert(group
->group_filtermode_isexcl
);
735 zassert(listcount(group
->group_source_list
) < 1);
737 source
= source_new (group
, src_addr
);
740 zlog_warn ("%s: Failure to create * source", __PRETTY_FUNCTION__
);
744 igmp_source_forward_start (source
);
747 void igmp_anysource_forward_stop(struct igmp_group
*group
)
749 struct igmp_source
*source
;
750 struct in_addr star
= { .s_addr
= 0 };
752 source
= igmp_find_source_by_addr (group
, star
);
754 igmp_source_forward_stop (source
);
757 static int fib_lookup_if_vif_index(struct in_addr addr
)
759 struct pim_zlookup_nexthop nexthop_tab
[PIM_NEXTHOP_IFINDEX_TAB_SIZE
];
762 ifindex_t first_ifindex
;
764 num_ifindex
= zclient_lookup_nexthop(qpim_zclient_lookup
, nexthop_tab
,
765 PIM_NEXTHOP_IFINDEX_TAB_SIZE
, addr
,
766 PIM_NEXTHOP_LOOKUP_MAX
);
767 if (num_ifindex
< 1) {
769 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
770 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
771 __FILE__
, __PRETTY_FUNCTION__
,
776 first_ifindex
= nexthop_tab
[0].ifindex
;
778 if (num_ifindex
> 1) {
780 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
781 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
782 __FILE__
, __PRETTY_FUNCTION__
,
783 num_ifindex
, addr_str
, first_ifindex
);
784 /* debug warning only, do not return */
787 if (PIM_DEBUG_ZEBRA
) {
789 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
790 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
791 __FILE__
, __PRETTY_FUNCTION__
,
792 first_ifindex
, ifindex2ifname(first_ifindex
), addr_str
);
795 vif_index
= pim_if_find_vifindex_by_ifindex(first_ifindex
);
799 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
800 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
801 __FILE__
, __PRETTY_FUNCTION__
,
802 vif_index
, addr_str
);
806 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
808 if (vif_index
> qpim_mroute_oif_highest_vif_index
) {
810 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
811 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
812 __FILE__
, __PRETTY_FUNCTION__
,
813 vif_index
, qpim_mroute_oif_highest_vif_index
, addr_str
);
815 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
816 __FILE__
, __PRETTY_FUNCTION__
,
817 ifindex2ifname(vif_index
),
826 static int del_oif(struct channel_oil
*channel_oil
,
827 struct interface
*oif
,
830 struct pim_interface
*pim_ifp
;
833 zassert(channel_oil
);
837 zassert(pim_ifp
->mroute_vif_index
>= 1);
838 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
839 zassert(pim_ifp
->mroute_vif_index
<= qpim_mroute_oif_highest_vif_index
);
841 if (PIM_DEBUG_MROUTE
) {
843 char source_str
[100];
844 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
845 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
846 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
847 __FILE__
, __PRETTY_FUNCTION__
,
848 source_str
, group_str
,
849 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
852 /* Prevent single protocol from unsubscribing same interface from
853 channel (S,G) multiple times */
854 if (!(channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & proto_mask
)) {
856 char source_str
[100];
857 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
858 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
859 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
860 __FILE__
, __PRETTY_FUNCTION__
,
861 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
862 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
863 source_str
, group_str
);
867 /* Mark that protocol is no longer interested in this OIF */
868 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] &= ~proto_mask
;
870 /* Allow multiple protocols to unsubscribe same interface from
871 channel (S,G) multiple times, by silently ignoring requests while
872 there is at least one protocol interested in the channel */
873 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
875 /* Check the OIF keeps existing before returning, and only log
877 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
879 char source_str
[100];
880 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
881 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
882 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
883 __FILE__
, __PRETTY_FUNCTION__
,
884 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
885 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
886 source_str
, group_str
);
892 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
896 char source_str
[100];
897 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
898 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
899 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
900 __FILE__
, __PRETTY_FUNCTION__
,
901 oif
->name
, pim_ifp
->mroute_vif_index
,
902 source_str
, group_str
);
906 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = 0;
908 if (pim_mroute_add(channel_oil
)) {
910 char source_str
[100];
911 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
912 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
913 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
914 __FILE__
, __PRETTY_FUNCTION__
,
915 oif
->name
, pim_ifp
->mroute_vif_index
,
916 source_str
, group_str
);
918 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
922 --channel_oil
->oil_size
;
924 if (channel_oil
->oil_size
< 1) {
925 if (pim_mroute_del(channel_oil
)) {
926 /* just log a warning in case of failure */
928 char source_str
[100];
929 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
930 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
931 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
932 __FILE__
, __PRETTY_FUNCTION__
,
933 source_str
, group_str
);
937 if (PIM_DEBUG_MROUTE
) {
939 char source_str
[100];
940 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
941 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
942 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
943 __FILE__
, __PRETTY_FUNCTION__
,
944 source_str
, group_str
,
945 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
951 void igmp_source_forward_start(struct igmp_source
*source
)
953 struct igmp_group
*group
;
956 if (PIM_DEBUG_IGMP_TRACE
) {
957 char source_str
[100];
959 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
960 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
961 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
963 source_str
, group_str
,
964 source
->source_group
->group_igmp_sock
->fd
,
965 source
->source_group
->group_igmp_sock
->interface
->name
,
966 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
969 /* Prevent IGMP interface from installing multicast route multiple
971 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
975 group
= source
->source_group
;
977 if (!source
->source_channel_oil
) {
978 struct in_addr vif_source
;
979 struct pim_interface
*pim_oif
;
981 if (!pim_rp_set_upstream_addr (&vif_source
, source
->source_addr
))
984 int input_iface_vif_index
= fib_lookup_if_vif_index(vif_source
);
985 if (input_iface_vif_index
< 1) {
986 char source_str
[100];
987 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
988 zlog_warn("%s %s: could not find input interface for source %s",
989 __FILE__
, __PRETTY_FUNCTION__
,
995 Protect IGMP against adding looped MFC entries created by both
996 source and receiver attached to the same interface. See TODO
999 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
1001 zlog_warn("%s: multicast not enabled on oif=%s ?",
1002 __PRETTY_FUNCTION__
,
1003 source
->source_group
->group_igmp_sock
->interface
->name
);
1006 if (pim_oif
->mroute_vif_index
< 1) {
1007 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1008 __FILE__
, __PRETTY_FUNCTION__
,
1009 source
->source_group
->group_igmp_sock
->interface
->name
,
1010 pim_oif
->mroute_vif_index
);
1013 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
1014 /* ignore request for looped MFC entry */
1015 if (PIM_DEBUG_IGMP_TRACE
) {
1016 char source_str
[100];
1017 char group_str
[100];
1018 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1019 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1020 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1021 __PRETTY_FUNCTION__
,
1022 source_str
, group_str
,
1023 source
->source_group
->group_igmp_sock
->fd
,
1024 source
->source_group
->group_igmp_sock
->interface
->name
,
1025 input_iface_vif_index
);
1030 source
->source_channel_oil
= pim_channel_oil_add(group
->group_addr
,
1031 source
->source_addr
,
1032 input_iface_vif_index
);
1033 if (!source
->source_channel_oil
) {
1034 char group_str
[100];
1035 char source_str
[100];
1036 pim_inet4_dump("<group?>", group
->group_addr
, group_str
, sizeof(group_str
));
1037 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1038 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1039 __FILE__
, __PRETTY_FUNCTION__
,
1040 source_str
, group_str
);
1045 result
= pim_channel_add_oif(source
->source_channel_oil
,
1046 group
->group_igmp_sock
->interface
,
1047 PIM_OIF_FLAG_PROTO_IGMP
);
1049 zlog_warn("%s: add_oif() failed with return=%d",
1055 Feed IGMPv3-gathered local membership information into PIM
1056 per-interface (S,G) state.
1058 pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
,
1059 source
->source_addr
, group
->group_addr
);
1061 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1065 igmp_source_forward_stop: stop fowarding, but keep the source
1066 igmp_source_delete: stop fowarding, and delete the source
1068 void igmp_source_forward_stop(struct igmp_source
*source
)
1070 struct igmp_group
*group
;
1073 if (PIM_DEBUG_IGMP_TRACE
) {
1074 char source_str
[100];
1075 char group_str
[100];
1076 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1077 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1078 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1079 __PRETTY_FUNCTION__
,
1080 source_str
, group_str
,
1081 source
->source_group
->group_igmp_sock
->fd
,
1082 source
->source_group
->group_igmp_sock
->interface
->name
,
1083 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1086 /* Prevent IGMP interface from removing multicast route multiple
1088 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1092 group
= source
->source_group
;
1095 It appears that in certain circumstances that
1096 igmp_source_forward_stop is called when IGMP forwarding
1097 was not enabled in oif_flags for this outgoing interface.
1098 Possibly because of multiple calls. When that happens, we
1099 enter the below if statement and this function returns early
1100 which in turn triggers the calling function to assert.
1101 Making the call to del_oif and ignoring the return code
1102 fixes the issue without ill effect, similar to
1103 pim_forward_stop below.
1105 result
= del_oif(source
->source_channel_oil
,
1106 group
->group_igmp_sock
->interface
,
1107 PIM_OIF_FLAG_PROTO_IGMP
);
1109 zlog_warn("%s: del_oif() failed with return=%d",
1115 Feed IGMPv3-gathered local membership information into PIM
1116 per-interface (S,G) state.
1118 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1119 source
->source_addr
, group
->group_addr
);
1121 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1124 void pim_forward_start(struct pim_ifchannel
*ch
)
1126 struct pim_upstream
*up
= ch
->upstream
;
1128 if (PIM_DEBUG_PIM_TRACE
) {
1129 char source_str
[100];
1130 char group_str
[100];
1131 char upstream_str
[100];
1133 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1134 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1135 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
, sizeof(upstream_str
));
1136 zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
1137 __PRETTY_FUNCTION__
,
1138 source_str
, group_str
, ch
->interface
->name
, upstream_str
);
1141 if (!up
->channel_oil
) {
1142 int input_iface_vif_index
= fib_lookup_if_vif_index(up
->upstream_addr
);
1143 if (input_iface_vif_index
< 1) {
1144 char source_str
[100];
1145 pim_inet4_dump("<source?>", up
->source_addr
, source_str
, sizeof(source_str
));
1146 zlog_warn("%s %s: could not find input interface for source %s",
1147 __FILE__
, __PRETTY_FUNCTION__
,
1152 up
->channel_oil
= pim_channel_oil_add(up
->group_addr
, up
->source_addr
,
1153 input_iface_vif_index
);
1154 if (!up
->channel_oil
) {
1155 char group_str
[100];
1156 char source_str
[100];
1157 pim_inet4_dump("<group?>", up
->group_addr
, group_str
, sizeof(group_str
));
1158 pim_inet4_dump("<source?>", up
->source_addr
, source_str
, sizeof(source_str
));
1159 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1160 __FILE__
, __PRETTY_FUNCTION__
,
1161 source_str
, group_str
);
1166 pim_channel_add_oif(up
->channel_oil
,
1168 PIM_OIF_FLAG_PROTO_PIM
);
1171 void pim_forward_stop(struct pim_ifchannel
*ch
)
1173 struct pim_upstream
*up
= ch
->upstream
;
1175 if (PIM_DEBUG_PIM_TRACE
) {
1176 char source_str
[100];
1177 char group_str
[100];
1178 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1179 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1180 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1181 __PRETTY_FUNCTION__
,
1182 source_str
, group_str
, ch
->interface
->name
);
1185 if (!up
->channel_oil
) {
1186 char source_str
[100];
1187 char group_str
[100];
1188 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1189 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1190 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1191 __PRETTY_FUNCTION__
,
1192 source_str
, group_str
, ch
->interface
->name
);
1197 del_oif(up
->channel_oil
,
1199 PIM_OIF_FLAG_PROTO_PIM
);