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
;
536 unsigned long ifindex
;
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_getc(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 case ZEBRA_IPV4_ROUTE_ADD
:
620 if (PIM_DEBUG_ZEBRA
) {
621 char buf
[2][INET_ADDRSTRLEN
];
622 zlog_debug("%s: add %s %s/%d "
623 "nexthop %s ifindex %ld metric%s %u distance%s %u",
625 zebra_route_string(api
.type
),
626 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
628 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
630 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
632 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
636 case ZEBRA_REDISTRIBUTE_IPV4_DEL
:
637 case ZEBRA_IPV4_ROUTE_DELETE
:
638 if (PIM_DEBUG_ZEBRA
) {
639 char buf
[2][INET_ADDRSTRLEN
];
640 zlog_debug("%s: delete %s %s/%d "
641 "nexthop %s ifindex %ld metric%s %u distance%s %u",
643 zebra_route_string(api
.type
),
644 inet_ntop(AF_INET
, &p
.prefix
, buf
[0], sizeof(buf
[0])),
646 inet_ntop(AF_INET
, &nexthop
, buf
[1], sizeof(buf
[1])),
648 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_METRIC
) ? "-recv" : "-miss",
650 CHECK_FLAG(api
.message
, ZAPI_MESSAGE_DISTANCE
) ? "-recv" : "-miss",
655 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__
, command
);
659 sched_rpf_cache_refresh();
665 pim_zebra_connected (struct zclient
*zclient
)
667 zclient_send_reg_requests (zclient
, VRF_DEFAULT
);
669 void pim_zebra_init(char *zebra_sock_path
)
674 zclient_serv_path_set(zebra_sock_path
);
676 #ifdef HAVE_TCP_ZEBRA
677 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT
);
679 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
682 /* Socket for receiving updates from Zebra daemon */
683 qpim_zclient_update
= zclient_new (master
);
685 qpim_zclient_update
->zebra_connected
= pim_zebra_connected
;
686 qpim_zclient_update
->router_id_update
= pim_router_id_update_zebra
;
687 qpim_zclient_update
->interface_add
= pim_zebra_if_add
;
688 qpim_zclient_update
->interface_delete
= pim_zebra_if_del
;
689 qpim_zclient_update
->interface_up
= pim_zebra_if_state_up
;
690 qpim_zclient_update
->interface_down
= pim_zebra_if_state_down
;
691 qpim_zclient_update
->interface_address_add
= pim_zebra_if_address_add
;
692 qpim_zclient_update
->interface_address_delete
= pim_zebra_if_address_del
;
693 qpim_zclient_update
->ipv4_route_add
= redist_read_ipv4_route
;
694 qpim_zclient_update
->ipv4_route_delete
= redist_read_ipv4_route
;
695 qpim_zclient_update
->redistribute_route_ipv4_add
= redist_read_ipv4_route
;
696 qpim_zclient_update
->redistribute_route_ipv4_del
= redist_read_ipv4_route
;
698 zclient_init(qpim_zclient_update
, ZEBRA_ROUTE_PIM
, 0);
699 if (PIM_DEBUG_PIM_TRACE
) {
700 zlog_info("zclient_init cleared redistribution request");
703 zassert(qpim_zclient_update
->redist_default
== ZEBRA_ROUTE_PIM
);
705 /* Request all redistribution */
706 for (i
= 0; i
< ZEBRA_ROUTE_MAX
; i
++) {
707 if (i
== qpim_zclient_update
->redist_default
)
709 vrf_bitmap_set (qpim_zclient_update
->redist
[AFI_IP
][i
], VRF_DEFAULT
);;
710 if (PIM_DEBUG_PIM_TRACE
) {
711 zlog_debug("%s: requesting redistribution for %s (%i)",
712 __PRETTY_FUNCTION__
, zebra_route_string(i
), i
);
716 /* Request default information */
717 zclient_redistribute_default (ZEBRA_REDISTRIBUTE_DEFAULT_ADD
,
718 qpim_zclient_update
, VRF_DEFAULT
);
720 if (PIM_DEBUG_PIM_TRACE
) {
721 zlog_info("%s: requesting default information redistribution",
722 __PRETTY_FUNCTION__
);
724 zlog_notice("%s: zclient update socket initialized",
725 __PRETTY_FUNCTION__
);
728 zassert(!qpim_zclient_lookup
);
729 qpim_zclient_lookup
= zclient_lookup_new();
730 zassert(qpim_zclient_lookup
);
733 void igmp_anysource_forward_start(struct igmp_group
*group
)
735 struct igmp_source
*source
;
736 struct in_addr src_addr
= { .s_addr
= 0 };
737 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
738 zassert(group
->group_filtermode_isexcl
);
739 zassert(listcount(group
->group_source_list
) < 1);
741 source
= source_new (group
, src_addr
);
744 zlog_warn ("%s: Failure to create * source", __PRETTY_FUNCTION__
);
748 igmp_source_forward_start (source
);
751 void igmp_anysource_forward_stop(struct igmp_group
*group
)
753 struct igmp_source
*source
;
754 struct in_addr star
= { .s_addr
= 0 };
756 source
= igmp_find_source_by_addr (group
, star
);
758 igmp_source_forward_stop (source
);
761 static int fib_lookup_if_vif_index(struct in_addr addr
)
763 struct pim_zlookup_nexthop nexthop_tab
[PIM_NEXTHOP_IFINDEX_TAB_SIZE
];
768 num_ifindex
= zclient_lookup_nexthop(qpim_zclient_lookup
, nexthop_tab
,
769 PIM_NEXTHOP_IFINDEX_TAB_SIZE
, addr
,
770 PIM_NEXTHOP_LOOKUP_MAX
);
771 if (num_ifindex
< 1) {
773 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
774 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
775 __FILE__
, __PRETTY_FUNCTION__
,
780 first_ifindex
= nexthop_tab
[0].ifindex
;
782 if (num_ifindex
> 1) {
784 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
785 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
786 __FILE__
, __PRETTY_FUNCTION__
,
787 num_ifindex
, addr_str
, first_ifindex
);
788 /* debug warning only, do not return */
791 if (PIM_DEBUG_ZEBRA
) {
793 pim_inet4_dump("<ifaddr?>", addr
, addr_str
, sizeof(addr_str
));
794 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
795 __FILE__
, __PRETTY_FUNCTION__
,
796 first_ifindex
, ifindex2ifname(first_ifindex
), addr_str
);
799 vif_index
= pim_if_find_vifindex_by_ifindex(first_ifindex
);
803 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
804 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
805 __FILE__
, __PRETTY_FUNCTION__
,
806 vif_index
, addr_str
);
810 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
812 if (vif_index
> qpim_mroute_oif_highest_vif_index
) {
814 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
815 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
816 __FILE__
, __PRETTY_FUNCTION__
,
817 vif_index
, qpim_mroute_oif_highest_vif_index
, addr_str
);
819 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
820 __FILE__
, __PRETTY_FUNCTION__
,
821 ifindex2ifname(vif_index
),
830 static int del_oif(struct channel_oil
*channel_oil
,
831 struct interface
*oif
,
834 struct pim_interface
*pim_ifp
;
837 zassert(channel_oil
);
841 zassert(pim_ifp
->mroute_vif_index
>= 1);
842 zassert(qpim_mroute_oif_highest_vif_index
< MAXVIFS
);
843 zassert(pim_ifp
->mroute_vif_index
<= qpim_mroute_oif_highest_vif_index
);
845 if (PIM_DEBUG_MROUTE
) {
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_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
851 __FILE__
, __PRETTY_FUNCTION__
,
852 source_str
, group_str
,
853 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
856 /* Prevent single protocol from unsubscribing same interface from
857 channel (S,G) multiple times */
858 if (!(channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & proto_mask
)) {
860 char source_str
[100];
861 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
862 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
863 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
864 __FILE__
, __PRETTY_FUNCTION__
,
865 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
866 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
867 source_str
, group_str
);
871 /* Mark that protocol is no longer interested in this OIF */
872 channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] &= ~proto_mask
;
874 /* Allow multiple protocols to unsubscribe same interface from
875 channel (S,G) multiple times, by silently ignoring requests while
876 there is at least one protocol interested in the channel */
877 if (channel_oil
->oif_flags
[pim_ifp
->mroute_vif_index
] & PIM_OIF_FLAG_PROTO_ANY
) {
879 /* Check the OIF keeps existing before returning, and only log
881 if (channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] < 1) {
883 char source_str
[100];
884 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
885 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
886 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
887 __FILE__
, __PRETTY_FUNCTION__
,
888 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
,
889 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
],
890 source_str
, group_str
);
896 old_ttl
= channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
];
900 char source_str
[100];
901 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
902 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
903 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
904 __FILE__
, __PRETTY_FUNCTION__
,
905 oif
->name
, pim_ifp
->mroute_vif_index
,
906 source_str
, group_str
);
910 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = 0;
912 if (pim_mroute_add(channel_oil
)) {
914 char source_str
[100];
915 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
916 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
917 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
918 __FILE__
, __PRETTY_FUNCTION__
,
919 oif
->name
, pim_ifp
->mroute_vif_index
,
920 source_str
, group_str
);
922 channel_oil
->oil
.mfcc_ttls
[pim_ifp
->mroute_vif_index
] = old_ttl
;
926 --channel_oil
->oil_size
;
928 if (channel_oil
->oil_size
< 1) {
929 if (pim_mroute_del(channel_oil
)) {
930 /* just log a warning in case of failure */
932 char source_str
[100];
933 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
934 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
935 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
936 __FILE__
, __PRETTY_FUNCTION__
,
937 source_str
, group_str
);
941 if (PIM_DEBUG_MROUTE
) {
943 char source_str
[100];
944 pim_inet4_dump("<group?>", channel_oil
->oil
.mfcc_mcastgrp
, group_str
, sizeof(group_str
));
945 pim_inet4_dump("<source?>", channel_oil
->oil
.mfcc_origin
, source_str
, sizeof(source_str
));
946 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
947 __FILE__
, __PRETTY_FUNCTION__
,
948 source_str
, group_str
,
949 proto_mask
, oif
->name
, pim_ifp
->mroute_vif_index
);
955 void igmp_source_forward_start(struct igmp_source
*source
)
957 struct igmp_group
*group
;
960 if (PIM_DEBUG_IGMP_TRACE
) {
961 char source_str
[100];
963 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
964 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
965 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
967 source_str
, group_str
,
968 source
->source_group
->group_igmp_sock
->fd
,
969 source
->source_group
->group_igmp_sock
->interface
->name
,
970 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
973 /* Prevent IGMP interface from installing multicast route multiple
975 if (IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
979 group
= source
->source_group
;
981 if (!source
->source_channel_oil
) {
982 struct in_addr vif_source
;
983 struct pim_interface
*pim_oif
;
985 if (!pim_rp_set_upstream_addr (&vif_source
, source
->source_addr
))
988 int input_iface_vif_index
= fib_lookup_if_vif_index(vif_source
);
989 if (input_iface_vif_index
< 1) {
990 char source_str
[100];
991 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
992 zlog_warn("%s %s: could not find input interface for source %s",
993 __FILE__
, __PRETTY_FUNCTION__
,
999 Protect IGMP against adding looped MFC entries created by both
1000 source and receiver attached to the same interface. See TODO
1003 pim_oif
= source
->source_group
->group_igmp_sock
->interface
->info
;
1005 zlog_warn("%s: multicast not enabled on oif=%s ?",
1006 __PRETTY_FUNCTION__
,
1007 source
->source_group
->group_igmp_sock
->interface
->name
);
1010 if (pim_oif
->mroute_vif_index
< 1) {
1011 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1012 __FILE__
, __PRETTY_FUNCTION__
,
1013 source
->source_group
->group_igmp_sock
->interface
->name
,
1014 pim_oif
->mroute_vif_index
);
1017 if (input_iface_vif_index
== pim_oif
->mroute_vif_index
) {
1018 /* ignore request for looped MFC entry */
1019 if (PIM_DEBUG_IGMP_TRACE
) {
1020 char source_str
[100];
1021 char group_str
[100];
1022 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1023 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1024 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1025 __PRETTY_FUNCTION__
,
1026 source_str
, group_str
,
1027 source
->source_group
->group_igmp_sock
->fd
,
1028 source
->source_group
->group_igmp_sock
->interface
->name
,
1029 input_iface_vif_index
);
1034 source
->source_channel_oil
= pim_channel_oil_add(group
->group_addr
,
1035 source
->source_addr
,
1036 input_iface_vif_index
);
1037 if (!source
->source_channel_oil
) {
1038 char group_str
[100];
1039 char source_str
[100];
1040 pim_inet4_dump("<group?>", group
->group_addr
, group_str
, sizeof(group_str
));
1041 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1042 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1043 __FILE__
, __PRETTY_FUNCTION__
,
1044 source_str
, group_str
);
1049 result
= pim_channel_add_oif(source
->source_channel_oil
,
1050 group
->group_igmp_sock
->interface
,
1051 PIM_OIF_FLAG_PROTO_IGMP
);
1053 zlog_warn("%s: add_oif() failed with return=%d",
1059 Feed IGMPv3-gathered local membership information into PIM
1060 per-interface (S,G) state.
1062 pim_ifchannel_local_membership_add(group
->group_igmp_sock
->interface
,
1063 source
->source_addr
, group
->group_addr
);
1065 IGMP_SOURCE_DO_FORWARDING(source
->source_flags
);
1069 igmp_source_forward_stop: stop fowarding, but keep the source
1070 igmp_source_delete: stop fowarding, and delete the source
1072 void igmp_source_forward_stop(struct igmp_source
*source
)
1074 struct igmp_group
*group
;
1077 if (PIM_DEBUG_IGMP_TRACE
) {
1078 char source_str
[100];
1079 char group_str
[100];
1080 pim_inet4_dump("<source?>", source
->source_addr
, source_str
, sizeof(source_str
));
1081 pim_inet4_dump("<group?>", source
->source_group
->group_addr
, group_str
, sizeof(group_str
));
1082 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1083 __PRETTY_FUNCTION__
,
1084 source_str
, group_str
,
1085 source
->source_group
->group_igmp_sock
->fd
,
1086 source
->source_group
->group_igmp_sock
->interface
->name
,
1087 IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
));
1090 /* Prevent IGMP interface from removing multicast route multiple
1092 if (!IGMP_SOURCE_TEST_FORWARDING(source
->source_flags
)) {
1096 group
= source
->source_group
;
1099 It appears that in certain circumstances that
1100 igmp_source_forward_stop is called when IGMP forwarding
1101 was not enabled in oif_flags for this outgoing interface.
1102 Possibly because of multiple calls. When that happens, we
1103 enter the below if statement and this function returns early
1104 which in turn triggers the calling function to assert.
1105 Making the call to del_oif and ignoring the return code
1106 fixes the issue without ill effect, similar to
1107 pim_forward_stop below.
1109 result
= del_oif(source
->source_channel_oil
,
1110 group
->group_igmp_sock
->interface
,
1111 PIM_OIF_FLAG_PROTO_IGMP
);
1113 zlog_warn("%s: del_oif() failed with return=%d",
1119 Feed IGMPv3-gathered local membership information into PIM
1120 per-interface (S,G) state.
1122 pim_ifchannel_local_membership_del(group
->group_igmp_sock
->interface
,
1123 source
->source_addr
, group
->group_addr
);
1125 IGMP_SOURCE_DONT_FORWARDING(source
->source_flags
);
1128 void pim_forward_start(struct pim_ifchannel
*ch
)
1130 struct pim_upstream
*up
= ch
->upstream
;
1132 if (PIM_DEBUG_PIM_TRACE
) {
1133 char source_str
[100];
1134 char group_str
[100];
1135 char upstream_str
[100];
1137 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1138 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1139 pim_inet4_dump("<upstream?>", up
->upstream_addr
, upstream_str
, sizeof(upstream_str
));
1140 zlog_debug("%s: (S,G)=(%s,%s) oif=%s(%s)",
1141 __PRETTY_FUNCTION__
,
1142 source_str
, group_str
, ch
->interface
->name
, upstream_str
);
1145 if (!up
->channel_oil
) {
1146 int input_iface_vif_index
= fib_lookup_if_vif_index(up
->upstream_addr
);
1147 if (input_iface_vif_index
< 1) {
1148 char source_str
[100];
1149 pim_inet4_dump("<source?>", up
->source_addr
, source_str
, sizeof(source_str
));
1150 zlog_warn("%s %s: could not find input interface for source %s",
1151 __FILE__
, __PRETTY_FUNCTION__
,
1156 up
->channel_oil
= pim_channel_oil_add(up
->group_addr
, up
->source_addr
,
1157 input_iface_vif_index
);
1158 if (!up
->channel_oil
) {
1159 char group_str
[100];
1160 char source_str
[100];
1161 pim_inet4_dump("<group?>", up
->group_addr
, group_str
, sizeof(group_str
));
1162 pim_inet4_dump("<source?>", up
->source_addr
, source_str
, sizeof(source_str
));
1163 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1164 __FILE__
, __PRETTY_FUNCTION__
,
1165 source_str
, group_str
);
1170 pim_channel_add_oif(up
->channel_oil
,
1172 PIM_OIF_FLAG_PROTO_PIM
);
1175 void pim_forward_stop(struct pim_ifchannel
*ch
)
1177 struct pim_upstream
*up
= ch
->upstream
;
1179 if (PIM_DEBUG_PIM_TRACE
) {
1180 char source_str
[100];
1181 char group_str
[100];
1182 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1183 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1184 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1185 __PRETTY_FUNCTION__
,
1186 source_str
, group_str
, ch
->interface
->name
);
1189 if (!up
->channel_oil
) {
1190 char source_str
[100];
1191 char group_str
[100];
1192 pim_inet4_dump("<source?>", ch
->source_addr
, source_str
, sizeof(source_str
));
1193 pim_inet4_dump("<group?>", ch
->group_addr
, group_str
, sizeof(group_str
));
1194 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1195 __PRETTY_FUNCTION__
,
1196 source_str
, group_str
, ch
->interface
->name
);
1201 del_oif(up
->channel_oil
,
1203 PIM_OIF_FLAG_PROTO_PIM
);