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 /* Router-id update message from zebra. */
55 static int pim_router_id_update_zebra(int command, struct zclient *zclient,
56 zebra_size_t length, vrf_id_t vrf_id)
58 struct prefix router_id;
60 zebra_router_id_update_read(zclient->ibuf, &router_id);
65 static int pim_zebra_if_add(int command, struct zclient *zclient,
66 zebra_size_t length, vrf_id_t vrf_id)
68 struct interface *ifp;
71 zebra api adds/dels interfaces using the same call
72 interface_add_read below, see comments in lib/zclient.c
74 ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
78 if (PIM_DEBUG_ZEBRA) {
79 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
81 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
82 ifp->mtu, if_is_operative(ifp));
85 if (if_is_operative(ifp))
86 pim_if_addr_add_all(ifp);
91 static int pim_zebra_if_del(int command, struct zclient *zclient,
92 zebra_size_t length, vrf_id_t vrf_id)
94 struct interface *ifp;
97 zebra api adds/dels interfaces using the same call
98 interface_add_read below, see comments in lib/zclient.c
100 comments in lib/zclient.c seem to indicate that calling
101 zebra_interface_add_read is the correct call, but that
102 results in an attemted out of bounds read which causes
103 pimd to assert. Other clients use zebra_interface_state_read
104 and it appears to work just fine.
106 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
110 if (PIM_DEBUG_ZEBRA) {
111 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
113 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
114 ifp->mtu, if_is_operative(ifp));
117 if (!if_is_operative(ifp))
118 pim_if_addr_del_all(ifp);
123 static int pim_zebra_if_state_up(int command, struct zclient *zclient,
124 zebra_size_t length, vrf_id_t vrf_id)
126 struct interface *ifp;
129 zebra api notifies interface up/down events by using the same call
130 zebra_interface_state_read below, see comments in lib/zclient.c
132 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
136 if (PIM_DEBUG_ZEBRA) {
137 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
139 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
140 ifp->mtu, if_is_operative(ifp));
143 if (if_is_operative(ifp)) {
145 pim_if_addr_add_all() suffices for bringing up both IGMP and PIM
147 pim_if_addr_add_all(ifp);
153 static int pim_zebra_if_state_down(int command, struct zclient *zclient,
154 zebra_size_t length, vrf_id_t vrf_id)
156 struct interface *ifp;
159 zebra api notifies interface up/down events by using the same call
160 zebra_interface_state_read below, see comments in lib/zclient.c
162 ifp = zebra_interface_state_read(zclient->ibuf, vrf_id);
166 if (PIM_DEBUG_ZEBRA) {
167 zlog_debug("%s: %s index %d flags %ld metric %d mtu %d operative %d",
169 ifp->name, ifp->ifindex, (long)ifp->flags, ifp->metric,
170 ifp->mtu, if_is_operative(ifp));
173 if (!if_is_operative(ifp)) {
175 pim_if_addr_del_all() suffices for shutting down IGMP,
176 but not for shutting down PIM
178 pim_if_addr_del_all(ifp);
181 pim_sock_delete() closes the socket, stops read and timer threads,
182 and kills all neighbors.
185 pim_sock_delete(ifp, "link down");
192 #ifdef PIM_DEBUG_IFADDR_DUMP
193 static void dump_if_address(struct interface *ifp)
195 struct connected *ifc;
196 struct listnode *node;
198 zlog_debug("%s %s: interface %s addresses:",
199 __FILE__, __PRETTY_FUNCTION__,
202 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
203 struct prefix *p = ifc->address;
205 if (p->family != AF_INET)
208 zlog_debug("%s %s: interface %s address %s %s",
209 __FILE__, __PRETTY_FUNCTION__,
211 inet_ntoa(p->u.prefix4),
212 CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
213 "secondary" : "primary");
218 static int pim_zebra_if_address_add(int command, struct zclient *zclient,
219 zebra_size_t length, vrf_id_t vrf_id)
225 zebra api notifies address adds/dels events by using the same call
226 interface_add_read below, see comments in lib/zclient.c
228 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, ...)
229 will add address to interface list by calling
230 connected_add_by_prefix()
232 c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
237 if (p->family != AF_INET)
240 if (PIM_DEBUG_ZEBRA) {
242 prefix2str(p, buf, BUFSIZ);
243 zlog_debug("%s: %s connected IP address %s flags %u %s",
245 c->ifp->name, buf, c->flags,
246 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
248 #ifdef PIM_DEBUG_IFADDR_DUMP
249 dump_if_address(c->ifp);
253 if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
254 /* trying to add primary address */
256 struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
257 if (primary_addr.s_addr != p->u.prefix4.s_addr) {
258 if (PIM_DEBUG_ZEBRA) {
259 /* but we had a primary address already */
264 prefix2str(p, buf, BUFSIZ);
265 pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
267 zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
269 c->ifp->name, old, buf);
271 SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
280 static int pim_zebra_if_address_del(int command, struct zclient *client,
281 zebra_size_t length, vrf_id_t vrf_id)
287 zebra api notifies address adds/dels events by using the same call
288 interface_add_read below, see comments in lib/zclient.c
290 zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, ...)
291 will remove address from interface list by calling
292 connected_delete_by_prefix()
294 c = zebra_interface_address_read(command, client->ibuf, vrf_id);
299 if (p->family != AF_INET)
302 if (PIM_DEBUG_ZEBRA) {
304 prefix2str(p, buf, BUFSIZ);
305 zlog_debug("%s: %s disconnected IP address %s flags %u %s",
307 c->ifp->name, buf, c->flags,
308 CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
310 #ifdef PIM_DEBUG_IFADDR_DUMP
311 dump_if_address(c->ifp);
315 pim_if_addr_del(c, 0);
320 static void scan_upstream_rpf_cache()
322 struct listnode *up_node;
323 struct listnode *up_nextnode;
324 struct pim_upstream *up;
326 for (ALL_LIST_ELEMENTS(qpim_upstream_list, up_node, up_nextnode, up)) {
327 struct pim_rpf old_rpf;
328 enum pim_rpf_result rpf_result;
330 rpf_result = pim_rpf_update(up, &old_rpf);
331 if (rpf_result == PIM_RPF_FAILURE)
334 if (rpf_result == PIM_RPF_CHANGED) {
336 if (up->join_state == PIM_UPSTREAM_JOINED) {
339 RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
341 Transitions from Joined State
343 RPF'(S,G) changes not due to an Assert
345 The upstream (S,G) state machine remains in Joined
346 state. Send Join(S,G) to the new upstream neighbor, which is
347 the new value of RPF'(S,G). Send Prune(S,G) to the old
348 upstream neighbor, which is the old value of RPF'(S,G). Set
349 the Join Timer (JT) to expire after t_periodic seconds.
353 /* send Prune(S,G) to the old upstream neighbor */
354 pim_joinprune_send(old_rpf.source_nexthop.interface,
360 /* send Join(S,G) to the current upstream neighbor */
361 pim_joinprune_send(up->rpf.source_nexthop.interface,
367 pim_upstream_join_timer_restart(up);
368 } /* up->join_state == PIM_UPSTREAM_JOINED */
370 /* FIXME can join_desired actually be changed by pim_rpf_update()
371 returning PIM_RPF_CHANGED ? */
372 pim_upstream_update_join_desired(up);
374 } /* PIM_RPF_CHANGED */
376 } /* for (qpim_upstream_list) */
382 struct listnode *node;
383 struct listnode *nextnode;
384 struct channel_oil *c_oil;
386 qpim_scan_oil_last = pim_time_monotonic_sec();
387 ++qpim_scan_oil_events;
389 for (ALL_LIST_ELEMENTS(qpim_channel_oil_list, node, nextnode, c_oil)) {
391 int input_iface_vif_index = fib_lookup_if_vif_index(c_oil->oil.mfcc_origin);
392 if (input_iface_vif_index < 1) {
393 char source_str[100];
395 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
396 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
397 zlog_warn("%s %s: could not find input interface for (S,G)=(%s,%s)",
398 __FILE__, __PRETTY_FUNCTION__,
399 source_str, group_str);
403 if (input_iface_vif_index == c_oil->oil.mfcc_parent) {
408 if (PIM_DEBUG_ZEBRA) {
409 struct interface *old_iif = pim_if_find_by_vif_index(c_oil->oil.mfcc_parent);
410 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
411 char source_str[100];
413 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
414 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
415 zlog_debug("%s %s: (S,G)=(%s,%s) input interface changed from %s vif_index=%d to %s vif_index=%d",
416 __FILE__, __PRETTY_FUNCTION__,
417 source_str, group_str,
418 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
419 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
422 /* new iif loops to existing oif ? */
423 if (c_oil->oil.mfcc_ttls[input_iface_vif_index]) {
424 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
426 if (PIM_DEBUG_ZEBRA) {
427 char source_str[100];
429 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
430 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
431 zlog_debug("%s %s: (S,G)=(%s,%s) new iif loops to existing oif: %s vif_index=%d",
432 __FILE__, __PRETTY_FUNCTION__,
433 source_str, group_str,
434 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
437 del_oif(c_oil, new_iif, PIM_OIF_FLAG_PROTO_ANY);
440 /* update iif vif_index */
441 old_vif_index = c_oil->oil.mfcc_parent;
442 c_oil->oil.mfcc_parent = input_iface_vif_index;
444 /* update kernel multicast forwarding cache (MFC) */
445 if (pim_mroute_add(&c_oil->oil)) {
446 /* just log warning */
447 struct interface *old_iif = pim_if_find_by_vif_index(old_vif_index);
448 struct interface *new_iif = pim_if_find_by_vif_index(input_iface_vif_index);
449 char source_str[100];
451 pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin, source_str, sizeof(source_str));
452 pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
453 zlog_warn("%s %s: (S,G)=(%s,%s) failure updating input interface from %s vif_index=%d to %s vif_index=%d",
454 __FILE__, __PRETTY_FUNCTION__,
455 source_str, group_str,
456 old_iif ? old_iif->name : "<old_iif?>", c_oil->oil.mfcc_parent,
457 new_iif ? new_iif->name : "<new_iif?>", input_iface_vif_index);
461 } /* for (qpim_channel_oil_list) */
464 static int on_rpf_cache_refresh(struct thread *t)
467 zassert(qpim_rpf_cache_refresher);
469 qpim_rpf_cache_refresher = 0;
471 /* update PIM protocol state */
472 scan_upstream_rpf_cache();
474 /* update kernel multicast forwarding cache (MFC) */
477 qpim_rpf_cache_refresh_last = pim_time_monotonic_sec();
478 ++qpim_rpf_cache_refresh_events;
483 static void sched_rpf_cache_refresh()
485 ++qpim_rpf_cache_refresh_requests;
487 if (qpim_rpf_cache_refresher) {
488 /* Refresh timer is already running */
492 /* Start refresh timer */
494 if (PIM_DEBUG_ZEBRA) {
495 zlog_debug("%s: triggering %ld msec timer",
497 qpim_rpf_cache_refresh_delay_msec);
500 THREAD_TIMER_MSEC_ON(master, qpim_rpf_cache_refresher,
501 on_rpf_cache_refresh,
502 0, qpim_rpf_cache_refresh_delay_msec);
505 static int redist_read_ipv4_route(int command, struct zclient *zclient,
506 zebra_size_t length, vrf_id_t vrf_id)
509 struct zapi_ipv4 api;
511 struct in_addr nexthop;
512 struct prefix_ipv4 p;
515 if (length < min_len) {
516 zlog_warn("%s %s: short buffer: length=%d min=%d",
517 __FILE__, __PRETTY_FUNCTION__,
526 /* Type, flags, message. */
527 api.type = stream_getc(s);
528 api.flags = stream_getc(s);
529 api.message = stream_getc(s);
531 /* IPv4 prefix length. */
532 memset(&p, 0, sizeof(struct prefix_ipv4));
534 p.prefixlen = stream_getc(s);
538 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? 5 : 0 +
539 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? 5 : 0 +
540 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? 1 : 0 +
541 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? 4 : 0;
543 if (PIM_DEBUG_ZEBRA) {
544 zlog_debug("%s %s: length=%d min_len=%d flags=%s%s%s%s",
545 __FILE__, __PRETTY_FUNCTION__,
547 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
548 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
549 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
550 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
553 if (length < min_len) {
554 zlog_warn("%s %s: short buffer: length=%d min_len=%d flags=%s%s%s%s",
555 __FILE__, __PRETTY_FUNCTION__,
557 CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP) ? "nh" : "",
558 CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX) ? " ifi" : "",
559 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? " dist" : "",
560 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? " metr" : "");
565 stream_get(&p.prefix, s, PSIZE(p.prefixlen));
567 /* Nexthop, ifindex, distance, metric. */
568 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP)) {
569 api.nexthop_num = stream_getc(s);
570 nexthop.s_addr = stream_get_ipv4(s);
572 if (CHECK_FLAG(api.message, ZAPI_MESSAGE_IFINDEX)) {
573 api.ifindex_num = stream_getc(s);
574 ifindex = stream_getl(s);
577 api.distance = CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ?
581 api.metric = CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ?
585 if (CHECK_FLAG (api.message, ZAPI_MESSAGE_TAG))
586 api.tag = stream_getl (s);
591 case ZEBRA_IPV4_ROUTE_ADD:
592 if (PIM_DEBUG_ZEBRA) {
593 char buf[2][INET_ADDRSTRLEN];
594 zlog_debug("%s: add %s %s/%d "
595 "nexthop %s ifindex %d metric%s %u distance%s %u",
597 zebra_route_string(api.type),
598 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
600 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
602 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
604 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
608 case ZEBRA_IPV4_ROUTE_DELETE:
609 if (PIM_DEBUG_ZEBRA) {
610 char buf[2][INET_ADDRSTRLEN];
611 zlog_debug("%s: delete %s %s/%d "
612 "nexthop %s ifindex %d metric%s %u distance%s %u",
614 zebra_route_string(api.type),
615 inet_ntop(AF_INET, &p.prefix, buf[0], sizeof(buf[0])),
617 inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),
619 CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC) ? "-recv" : "-miss",
621 CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE) ? "-recv" : "-miss",
626 zlog_warn("%s: unknown command=%d", __PRETTY_FUNCTION__, command);
630 sched_rpf_cache_refresh();
635 static void pim_zebra_connected(struct zclient *zclient)
637 zclient_send_requests(zclient, VRF_DEFAULT);
640 void pim_zebra_init (struct thread_master *master, char *zebra_sock_path)
645 zclient_serv_path_set(zebra_sock_path);
647 #ifdef HAVE_TCP_ZEBRA
648 zlog_notice("zclient update contacting ZEBRA daemon at socket TCP %s,%d", "127.0.0.1", ZEBRA_PORT);
650 zlog_notice("zclient update contacting ZEBRA daemon at socket UNIX %s", zclient_serv_path_get());
653 /* Socket for receiving updates from Zebra daemon */
654 qpim_zclient_update = zclient_new (master);
656 qpim_zclient_update->zebra_connected = pim_zebra_connected;
657 qpim_zclient_update->router_id_update = pim_router_id_update_zebra;
658 qpim_zclient_update->interface_add = pim_zebra_if_add;
659 qpim_zclient_update->interface_delete = pim_zebra_if_del;
660 qpim_zclient_update->interface_up = pim_zebra_if_state_up;
661 qpim_zclient_update->interface_down = pim_zebra_if_state_down;
662 qpim_zclient_update->interface_address_add = pim_zebra_if_address_add;
663 qpim_zclient_update->interface_address_delete = pim_zebra_if_address_del;
664 qpim_zclient_update->ipv4_route_add = redist_read_ipv4_route;
665 qpim_zclient_update->ipv4_route_delete = redist_read_ipv4_route;
667 zclient_init(qpim_zclient_update, ZEBRA_ROUTE_PIM);
668 if (PIM_DEBUG_PIM_TRACE) {
669 zlog_info("zclient_init cleared redistribution request");
672 zassert(qpim_zclient_update->redist_default == ZEBRA_ROUTE_PIM);
674 /* Request all redistribution */
675 for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
676 if (i == qpim_zclient_update->redist_default)
678 vrf_bitmap_set(qpim_zclient_update->redist[i], VRF_DEFAULT);
679 if (PIM_DEBUG_PIM_TRACE) {
680 zlog_debug("%s: requesting redistribution for %s (%i)",
681 __PRETTY_FUNCTION__, zebra_route_string(i), i);
685 /* Request default information */
686 vrf_bitmap_set(qpim_zclient_update->default_information, VRF_DEFAULT);
687 if (PIM_DEBUG_PIM_TRACE) {
688 zlog_info("%s: requesting default information redistribution",
689 __PRETTY_FUNCTION__);
691 zlog_notice("%s: zclient update socket initialized",
692 __PRETTY_FUNCTION__);
695 zassert(!qpim_zclient_lookup);
696 qpim_zclient_lookup = zclient_lookup_new();
697 zassert(qpim_zclient_lookup);
700 void igmp_anysource_forward_start(struct igmp_group *group)
702 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
703 zassert(group->group_filtermode_isexcl);
704 zassert(listcount(group->group_source_list) < 1);
706 if (PIM_DEBUG_IGMP_TRACE) {
707 zlog_debug("%s %s: UNIMPLEMENTED",
708 __FILE__, __PRETTY_FUNCTION__);
712 void igmp_anysource_forward_stop(struct igmp_group *group)
714 /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
715 zassert((!group->group_filtermode_isexcl) || (listcount(group->group_source_list) > 0));
717 if (PIM_DEBUG_IGMP_TRACE) {
718 zlog_debug("%s %s: UNIMPLEMENTED",
719 __FILE__, __PRETTY_FUNCTION__);
723 static int fib_lookup_if_vif_index(struct in_addr addr)
725 struct pim_zlookup_nexthop nexthop_tab[PIM_NEXTHOP_IFINDEX_TAB_SIZE];
728 ifindex_t first_ifindex;
730 num_ifindex = zclient_lookup_nexthop(qpim_zclient_lookup, nexthop_tab,
731 PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr,
732 PIM_NEXTHOP_LOOKUP_MAX);
733 if (num_ifindex < 1) {
735 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
736 zlog_warn("%s %s: could not find nexthop ifindex for address %s",
737 __FILE__, __PRETTY_FUNCTION__,
742 first_ifindex = nexthop_tab[0].ifindex;
744 if (num_ifindex > 1) {
746 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
747 zlog_info("%s %s: FIXME ignoring multiple nexthop ifindex'es num_ifindex=%d for address %s (using only ifindex=%d)",
748 __FILE__, __PRETTY_FUNCTION__,
749 num_ifindex, addr_str, first_ifindex);
750 /* debug warning only, do not return */
753 if (PIM_DEBUG_ZEBRA) {
755 pim_inet4_dump("<ifaddr?>", addr, addr_str, sizeof(addr_str));
756 zlog_debug("%s %s: found nexthop ifindex=%d (interface %s) for address %s",
757 __FILE__, __PRETTY_FUNCTION__,
758 first_ifindex, ifindex2ifname(first_ifindex), addr_str);
761 vif_index = pim_if_find_vifindex_by_ifindex(first_ifindex);
765 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
766 zlog_warn("%s %s: low vif_index=%d < 1 nexthop for address %s",
767 __FILE__, __PRETTY_FUNCTION__,
768 vif_index, addr_str);
772 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
774 if (vif_index > qpim_mroute_oif_highest_vif_index) {
776 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
777 zlog_warn("%s %s: high vif_index=%d > highest_vif_index=%d nexthop for address %s",
778 __FILE__, __PRETTY_FUNCTION__,
779 vif_index, qpim_mroute_oif_highest_vif_index, addr_str);
781 zlog_warn("%s %s: pim disabled on interface %s vif_index=%d ?",
782 __FILE__, __PRETTY_FUNCTION__,
783 ifindex2ifname(vif_index),
792 static int add_oif(struct channel_oil *channel_oil,
793 struct interface *oif,
796 struct pim_interface *pim_ifp;
799 zassert(channel_oil);
803 if (PIM_DEBUG_MROUTE) {
805 char source_str[100];
806 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
807 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
808 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
809 __FILE__, __PRETTY_FUNCTION__,
810 source_str, group_str,
811 proto_mask, oif->name, pim_ifp->mroute_vif_index);
814 if (pim_ifp->mroute_vif_index < 1) {
815 zlog_warn("%s %s: interface %s vif_index=%d < 1",
816 __FILE__, __PRETTY_FUNCTION__,
817 oif->name, pim_ifp->mroute_vif_index);
821 #ifdef PIM_ENFORCE_LOOPFREE_MFC
823 Prevent creating MFC entry with OIF=IIF.
825 This is a protection against implementation mistakes.
827 PIM protocol implicitely ensures loopfree multicast topology.
829 IGMP must be protected against adding looped MFC entries created
830 by both source and receiver attached to the same interface. See
833 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
835 char source_str[100];
836 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
837 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
838 zlog_warn("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
839 __FILE__, __PRETTY_FUNCTION__,
840 proto_mask, oif->name, pim_ifp->mroute_vif_index,
841 source_str, group_str);
846 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
847 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
849 /* Prevent single protocol from subscribing same interface to
850 channel (S,G) multiple times */
851 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
853 char source_str[100];
854 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
855 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
856 zlog_warn("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
857 __FILE__, __PRETTY_FUNCTION__,
858 proto_mask, oif->name, pim_ifp->mroute_vif_index,
859 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
860 source_str, group_str);
864 /* Allow other protocol to request subscription of same interface to
865 channel (S,G) multiple times, by silently ignoring further
867 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
869 /* Check the OIF really exists before returning, and only log
871 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
873 char source_str[100];
874 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
875 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
876 zlog_warn("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
877 __FILE__, __PRETTY_FUNCTION__,
878 proto_mask, oif->name, pim_ifp->mroute_vif_index,
879 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
880 source_str, group_str);
886 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
890 char source_str[100];
891 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
892 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
893 zlog_warn("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
894 __FILE__, __PRETTY_FUNCTION__,
895 oif->name, pim_ifp->mroute_vif_index,
896 source_str, group_str);
900 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
902 if (pim_mroute_add(&channel_oil->oil)) {
904 char source_str[100];
905 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
906 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
907 zlog_warn("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
908 __FILE__, __PRETTY_FUNCTION__,
909 oif->name, pim_ifp->mroute_vif_index,
910 source_str, group_str);
912 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
916 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
917 ++channel_oil->oil_size;
918 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
920 if (PIM_DEBUG_MROUTE) {
922 char source_str[100];
923 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
924 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
925 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
926 __FILE__, __PRETTY_FUNCTION__,
927 source_str, group_str,
928 proto_mask, oif->name, pim_ifp->mroute_vif_index);
934 static int del_oif(struct channel_oil *channel_oil,
935 struct interface *oif,
938 struct pim_interface *pim_ifp;
941 zassert(channel_oil);
945 zassert(pim_ifp->mroute_vif_index >= 1);
946 zassert(qpim_mroute_oif_highest_vif_index < MAXVIFS);
947 zassert(pim_ifp->mroute_vif_index <= qpim_mroute_oif_highest_vif_index);
949 if (PIM_DEBUG_MROUTE) {
951 char source_str[100];
952 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
953 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
954 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
955 __FILE__, __PRETTY_FUNCTION__,
956 source_str, group_str,
957 proto_mask, oif->name, pim_ifp->mroute_vif_index);
960 /* Prevent single protocol from unsubscribing same interface from
961 channel (S,G) multiple times */
962 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
964 char source_str[100];
965 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
966 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
967 zlog_warn("%s %s: nonexistent protocol mask %u removed OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
968 __FILE__, __PRETTY_FUNCTION__,
969 proto_mask, oif->name, pim_ifp->mroute_vif_index,
970 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
971 source_str, group_str);
975 /* Mark that protocol is no longer interested in this OIF */
976 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
978 /* Allow multiple protocols to unsubscribe same interface from
979 channel (S,G) multiple times, by silently ignoring requests while
980 there is at least one protocol interested in the channel */
981 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
983 /* Check the OIF keeps existing before returning, and only log
985 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
987 char source_str[100];
988 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
989 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
990 zlog_warn("%s %s: protocol mask %u removing nonexistent OIF %s (vif_index=%d, min_ttl=%d) from channel (S,G)=(%s,%s)",
991 __FILE__, __PRETTY_FUNCTION__,
992 proto_mask, oif->name, pim_ifp->mroute_vif_index,
993 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
994 source_str, group_str);
1000 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
1003 char group_str[100];
1004 char source_str[100];
1005 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1006 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1007 zlog_warn("%s %s: interface %s (vif_index=%d) is not output for channel (S,G)=(%s,%s)",
1008 __FILE__, __PRETTY_FUNCTION__,
1009 oif->name, pim_ifp->mroute_vif_index,
1010 source_str, group_str);
1014 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
1016 if (pim_mroute_add(&channel_oil->oil)) {
1017 char group_str[100];
1018 char source_str[100];
1019 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1020 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1021 zlog_warn("%s %s: could not remove output interface %s (vif_index=%d) from channel (S,G)=(%s,%s)",
1022 __FILE__, __PRETTY_FUNCTION__,
1023 oif->name, pim_ifp->mroute_vif_index,
1024 source_str, group_str);
1026 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
1030 --channel_oil->oil_size;
1032 if (channel_oil->oil_size < 1) {
1033 if (pim_mroute_del(&channel_oil->oil)) {
1034 /* just log a warning in case of failure */
1035 char group_str[100];
1036 char source_str[100];
1037 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1038 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1039 zlog_warn("%s %s: failure removing OIL for channel (S,G)=(%s,%s)",
1040 __FILE__, __PRETTY_FUNCTION__,
1041 source_str, group_str);
1045 if (PIM_DEBUG_MROUTE) {
1046 char group_str[100];
1047 char source_str[100];
1048 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
1049 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
1050 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
1051 __FILE__, __PRETTY_FUNCTION__,
1052 source_str, group_str,
1053 proto_mask, oif->name, pim_ifp->mroute_vif_index);
1059 void igmp_source_forward_start(struct igmp_source *source)
1061 struct igmp_group *group;
1064 if (PIM_DEBUG_IGMP_TRACE) {
1065 char source_str[100];
1066 char group_str[100];
1067 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1068 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1069 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1070 __PRETTY_FUNCTION__,
1071 source_str, group_str,
1072 source->source_group->group_igmp_sock->fd,
1073 source->source_group->group_igmp_sock->interface->name,
1074 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1077 /* Prevent IGMP interface from installing multicast route multiple
1079 if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1083 group = source->source_group;
1085 if (!source->source_channel_oil) {
1086 struct pim_interface *pim_oif;
1087 int input_iface_vif_index = fib_lookup_if_vif_index(source->source_addr);
1088 if (input_iface_vif_index < 1) {
1089 char source_str[100];
1090 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1091 zlog_warn("%s %s: could not find input interface for source %s",
1092 __FILE__, __PRETTY_FUNCTION__,
1098 Protect IGMP against adding looped MFC entries created by both
1099 source and receiver attached to the same interface. See TODO
1102 pim_oif = source->source_group->group_igmp_sock->interface->info;
1104 zlog_warn("%s: multicast not enabled on oif=%s ?",
1105 __PRETTY_FUNCTION__,
1106 source->source_group->group_igmp_sock->interface->name);
1109 if (pim_oif->mroute_vif_index < 1) {
1110 zlog_warn("%s %s: oif=%s vif_index=%d < 1",
1111 __FILE__, __PRETTY_FUNCTION__,
1112 source->source_group->group_igmp_sock->interface->name,
1113 pim_oif->mroute_vif_index);
1116 if (input_iface_vif_index == pim_oif->mroute_vif_index) {
1117 /* ignore request for looped MFC entry */
1118 if (PIM_DEBUG_IGMP_TRACE) {
1119 char source_str[100];
1120 char group_str[100];
1121 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1122 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1123 zlog_debug("%s: ignoring request for looped MFC entry (S,G)=(%s,%s): igmp_sock=%d oif=%s vif_index=%d",
1124 __PRETTY_FUNCTION__,
1125 source_str, group_str,
1126 source->source_group->group_igmp_sock->fd,
1127 source->source_group->group_igmp_sock->interface->name,
1128 input_iface_vif_index);
1133 source->source_channel_oil = pim_channel_oil_add(group->group_addr,
1134 source->source_addr,
1135 input_iface_vif_index);
1136 if (!source->source_channel_oil) {
1137 char group_str[100];
1138 char source_str[100];
1139 pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
1140 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1141 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1142 __FILE__, __PRETTY_FUNCTION__,
1143 source_str, group_str);
1148 result = add_oif(source->source_channel_oil,
1149 group->group_igmp_sock->interface,
1150 PIM_OIF_FLAG_PROTO_IGMP);
1152 zlog_warn("%s: add_oif() failed with return=%d",
1158 Feed IGMPv3-gathered local membership information into PIM
1159 per-interface (S,G) state.
1161 pim_ifchannel_local_membership_add(group->group_igmp_sock->interface,
1162 source->source_addr, group->group_addr);
1164 IGMP_SOURCE_DO_FORWARDING(source->source_flags);
1168 igmp_source_forward_stop: stop fowarding, but keep the source
1169 igmp_source_delete: stop fowarding, and delete the source
1171 void igmp_source_forward_stop(struct igmp_source *source)
1173 struct igmp_group *group;
1176 if (PIM_DEBUG_IGMP_TRACE) {
1177 char source_str[100];
1178 char group_str[100];
1179 pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
1180 pim_inet4_dump("<group?>", source->source_group->group_addr, group_str, sizeof(group_str));
1181 zlog_debug("%s: (S,G)=(%s,%s) igmp_sock=%d oif=%s fwd=%d",
1182 __PRETTY_FUNCTION__,
1183 source_str, group_str,
1184 source->source_group->group_igmp_sock->fd,
1185 source->source_group->group_igmp_sock->interface->name,
1186 IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
1189 /* Prevent IGMP interface from removing multicast route multiple
1191 if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
1195 group = source->source_group;
1198 It appears that in certain circumstances that
1199 igmp_source_forward_stop is called when IGMP forwarding
1200 was not enabled in oif_flags for this outgoing interface.
1201 Possibly because of multiple calls. When that happens, we
1202 enter the below if statement and this function returns early
1203 which in turn triggers the calling function to assert.
1204 Making the call to del_oif and ignoring the return code
1205 fixes the issue without ill effect, similar to
1206 pim_forward_stop below.
1208 result = del_oif(source->source_channel_oil,
1209 group->group_igmp_sock->interface,
1210 PIM_OIF_FLAG_PROTO_IGMP);
1212 zlog_warn("%s: del_oif() failed with return=%d",
1218 Feed IGMPv3-gathered local membership information into PIM
1219 per-interface (S,G) state.
1221 pim_ifchannel_local_membership_del(group->group_igmp_sock->interface,
1222 source->source_addr, group->group_addr);
1224 IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
1227 void pim_forward_start(struct pim_ifchannel *ch)
1229 struct pim_upstream *up = ch->upstream;
1231 if (PIM_DEBUG_PIM_TRACE) {
1232 char source_str[100];
1233 char group_str[100];
1234 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1235 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1236 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1237 __PRETTY_FUNCTION__,
1238 source_str, group_str, ch->interface->name);
1241 if (!up->channel_oil) {
1242 int input_iface_vif_index = fib_lookup_if_vif_index(up->source_addr);
1243 if (input_iface_vif_index < 1) {
1244 char source_str[100];
1245 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1246 zlog_warn("%s %s: could not find input interface for source %s",
1247 __FILE__, __PRETTY_FUNCTION__,
1252 up->channel_oil = pim_channel_oil_add(up->group_addr, up->source_addr,
1253 input_iface_vif_index);
1254 if (!up->channel_oil) {
1255 char group_str[100];
1256 char source_str[100];
1257 pim_inet4_dump("<group?>", up->group_addr, group_str, sizeof(group_str));
1258 pim_inet4_dump("<source?>", up->source_addr, source_str, sizeof(source_str));
1259 zlog_warn("%s %s: could not create OIL for channel (S,G)=(%s,%s)",
1260 __FILE__, __PRETTY_FUNCTION__,
1261 source_str, group_str);
1266 add_oif(up->channel_oil,
1268 PIM_OIF_FLAG_PROTO_PIM);
1271 void pim_forward_stop(struct pim_ifchannel *ch)
1273 struct pim_upstream *up = ch->upstream;
1275 if (PIM_DEBUG_PIM_TRACE) {
1276 char source_str[100];
1277 char group_str[100];
1278 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1279 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1280 zlog_debug("%s: (S,G)=(%s,%s) oif=%s",
1281 __PRETTY_FUNCTION__,
1282 source_str, group_str, ch->interface->name);
1285 if (!up->channel_oil) {
1286 char source_str[100];
1287 char group_str[100];
1288 pim_inet4_dump("<source?>", ch->source_addr, source_str, sizeof(source_str));
1289 pim_inet4_dump("<group?>", ch->group_addr, group_str, sizeof(group_str));
1290 zlog_warn("%s: (S,G)=(%s,%s) oif=%s missing channel OIL",
1291 __PRETTY_FUNCTION__,
1292 source_str, group_str, ch->interface->name);
1297 del_oif(up->channel_oil,
1299 PIM_OIF_FLAG_PROTO_PIM);