]> git.proxmox.com Git - mirror_frr.git/blobdiff - pimd/pim_zebra.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / pimd / pim_zebra.c
index 526fdcbc27741e7daf44be288edc531857eda8d2..e39eca7a2ccf464e6903c21d2df3984c5bf26e30 100644 (file)
@@ -1,20 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * PIM for Quagga
  * Copyright (C) 2008  Everton da Silva Marques
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -55,7 +42,6 @@ struct zclient *zclient;
 
 
 /* Router-id update message from zebra. */
-__attribute__((unused))
 static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
 {
        struct prefix router_id;
@@ -65,7 +51,6 @@ static int pim_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
        return 0;
 }
 
-__attribute__((unused))
 static int pim_zebra_interface_vrf_update(ZAPI_CALLBACK_ARGS)
 {
        struct interface *ifp;
@@ -158,12 +143,23 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
                        SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
                }
        }
+#else /* PIM_IPV != 4 */
+       if (p->family != PIM_AF)
+               return 0;
+#endif
 
        pim_if_addr_add(c);
        if (pim_ifp) {
                struct pim_instance *pim;
 
                pim = pim_get_pim_instance(vrf_id);
+               if (!pim) {
+                       if (PIM_DEBUG_ZEBRA)
+                               zlog_debug("%s: Unable to find pim instance",
+                                          __func__);
+                       return 0;
+               }
+
                pim_ifp->pim = pim;
 
                pim_rp_check_on_if_add(pim_ifp);
@@ -178,10 +174,6 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS)
                                pim_if_addr_add_all(ifp);
                }
        }
-#else /* PIM_IPV != 4 */
-       /* unused - for now */
-       (void)pim_ifp;
-#endif
        return 0;
 }
 
@@ -220,8 +212,7 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
 #endif
        }
 
-#if PIM_IPV == 4
-       if (p->family == AF_INET) {
+       if (p->family == PIM_AF) {
                struct pim_instance *pim;
 
                pim = vrf->info;
@@ -229,7 +220,6 @@ static int pim_zebra_if_address_del(ZAPI_CALLBACK_ARGS)
                pim_rp_setup(pim);
                pim_i_am_rp_re_evaluate(pim);
        }
-#endif
 
        connected_free(&c);
        return 0;
@@ -252,7 +242,7 @@ void pim_zebra_update_all_interfaces(struct pim_instance *pim)
                        struct pim_rpf rpf;
 
                        rpf.source_nexthop.interface = ifp;
-                       pim_addr_to_prefix(&rpf.rpf_addr, us->address);
+                       rpf.rpf_addr = us->address;
                        pim_joinprune_send(&rpf, us->us);
                        pim_jp_agg_clear_group(us->us);
                }
@@ -266,8 +256,8 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim,
        if (old->source_nexthop.interface) {
                struct pim_neighbor *nbr;
 
-               nbr = pim_neighbor_find_prefix(old->source_nexthop.interface,
-                                              &old->rpf_addr);
+               nbr = pim_neighbor_find(old->source_nexthop.interface,
+                                       old->rpf_addr);
                if (nbr)
                        pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr);
 
@@ -449,6 +439,7 @@ static void pim_zebra_connected(struct zclient *zclient)
 static void pim_zebra_capabilities(struct zclient_capabilities *cap)
 {
        router->mlag_role = cap->role;
+       router->multipath = cap->ecmp;
 }
 
 static zclient_handler *const pim_handlers[] = {
@@ -456,10 +447,10 @@ static zclient_handler *const pim_handlers[] = {
        [ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del,
 
        [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update,
-#if PIM_IPV == 4
        [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra,
        [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update,
 
+#if PIM_IPV == 4
        [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc,
        [ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc,
 
@@ -486,335 +477,6 @@ void pim_zebra_init(void)
        zclient_lookup_new();
 }
 
-#if PIM_IPV == 4
-void igmp_anysource_forward_start(struct pim_instance *pim,
-                                 struct gm_group *group)
-{
-       struct gm_source *source;
-       struct in_addr src_addr = {.s_addr = 0};
-       /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
-       assert(group->group_filtermode_isexcl);
-       assert(listcount(group->group_source_list) < 1);
-
-       source = igmp_get_source_by_addr(group, src_addr, NULL);
-       if (!source) {
-               zlog_warn("%s: Failure to create * source", __func__);
-               return;
-       }
-
-       igmp_source_forward_start(pim, source);
-}
-
-void igmp_anysource_forward_stop(struct gm_group *group)
-{
-       struct gm_source *source;
-       struct in_addr star = {.s_addr = 0};
-
-       source = igmp_find_source_by_addr(group, star);
-       if (source)
-               igmp_source_forward_stop(source);
-}
-
-static void igmp_source_forward_reevaluate_one(struct pim_instance *pim,
-                                              struct gm_source *source)
-{
-       pim_sgaddr sg;
-       struct gm_group *group = source->source_group;
-       struct pim_ifchannel *ch;
-
-       if ((source->source_addr.s_addr != INADDR_ANY)
-           || !IGMP_SOURCE_TEST_FORWARDING(source->source_flags))
-               return;
-
-       memset(&sg, 0, sizeof(sg));
-       sg.src = source->source_addr;
-       sg.grp = group->group_addr;
-
-       ch = pim_ifchannel_find(group->interface, &sg);
-       if (pim_is_grp_ssm(pim, group->group_addr)) {
-               /* If SSM group withdraw local membership */
-               if (ch
-                   && (ch->local_ifmembership == PIM_IFMEMBERSHIP_INCLUDE)) {
-                       if (PIM_DEBUG_PIM_EVENTS)
-                               zlog_debug("local membership del for %pSG as G is now SSM",
-                                          &sg);
-                       pim_ifchannel_local_membership_del(group->interface,
-                                                          &sg);
-               }
-       } else {
-               /* If ASM group add local membership */
-               if (!ch
-                   || (ch->local_ifmembership == PIM_IFMEMBERSHIP_NOINFO)) {
-                       if (PIM_DEBUG_PIM_EVENTS)
-                               zlog_debug("local membership add for %pSG as G is now ASM",
-                                          &sg);
-                       pim_ifchannel_local_membership_add(
-                               group->interface, &sg, false /*is_vxlan*/);
-               }
-       }
-}
-
-void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
-{
-       struct interface *ifp;
-
-       FOR_ALL_INTERFACES (pim->vrf, ifp) {
-               struct pim_interface *pim_ifp = ifp->info;
-               struct listnode *grpnode;
-               struct gm_group *grp;
-               struct pim_ifchannel *ch, *ch_temp;
-
-               if (!pim_ifp)
-                       continue;
-
-               /* scan igmp groups */
-               for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode,
-                                         grp)) {
-                       struct listnode *srcnode;
-                       struct gm_source *src;
-
-                       /* scan group sources */
-                       for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
-                                                 srcnode, src)) {
-                               igmp_source_forward_reevaluate_one(pim, src);
-                       } /* scan group sources */
-               }        /* scan igmp groups */
-
-               RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
-                                ch_temp) {
-                       if (pim_is_grp_ssm(pim, ch->sg.grp)) {
-                               if (pim_addr_is_any(ch->sg.src))
-                                       pim_ifchannel_delete(ch);
-                       }
-               }
-       } /* scan interfaces */
-}
-
-void igmp_source_forward_start(struct pim_instance *pim,
-                              struct gm_source *source)
-{
-       struct pim_interface *pim_oif;
-       struct gm_group *group;
-       pim_sgaddr sg;
-       int result;
-       int input_iface_vif_index = 0;
-
-       memset(&sg, 0, sizeof(sg));
-       sg.src = source->source_addr;
-       sg.grp = source->source_group->group_addr;
-
-       if (PIM_DEBUG_IGMP_TRACE) {
-               zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
-                          source->source_group->interface->name,
-                          IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
-       }
-
-       /* Prevent IGMP interface from installing multicast route multiple
-          times */
-       if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
-               return;
-       }
-
-       group = source->source_group;
-       pim_oif = group->interface->info;
-       if (!pim_oif) {
-               if (PIM_DEBUG_IGMP_TRACE) {
-                       zlog_debug("%s: multicast not enabled on oif=%s ?",
-                                  __func__,
-                                  source->source_group->interface->name);
-               }
-               return;
-       }
-
-       if (!source->source_channel_oil) {
-               pim_addr vif_source;
-               struct prefix src, grp;
-               struct pim_nexthop nexthop;
-               struct pim_upstream *up = NULL;
-
-               if (!pim_rp_set_upstream_addr(pim, &vif_source,
-                                             source->source_addr, sg.grp)) {
-                       /*Create a dummy channel oil */
-                       source->source_channel_oil =
-                               pim_channel_oil_add(pim, &sg, __func__);
-               }
-
-               else {
-                       pim_addr_to_prefix(&src, vif_source); // RP or Src addr
-                       pim_addr_to_prefix(&grp, sg.grp);
-
-                       up = pim_upstream_find(pim, &sg);
-                       if (up) {
-                               memcpy(&nexthop, &up->rpf.source_nexthop,
-                                      sizeof(struct pim_nexthop));
-                               pim_ecmp_nexthop_lookup(pim, &nexthop, &src,
-                                                       &grp, 0);
-                               if (nexthop.interface)
-                                       input_iface_vif_index =
-                                               pim_if_find_vifindex_by_ifindex(
-                                                       pim,
-                                                       nexthop.interface->ifindex);
-                       } else
-                               input_iface_vif_index =
-                                       pim_ecmp_fib_lookup_if_vif_index(
-                                               pim, &src, &grp);
-
-                       if (PIM_DEBUG_ZEBRA)
-                               zlog_debug(
-                                       "%s: NHT %pSG vif_source %pPAs vif_index:%d ",
-                                       __func__, &sg, &vif_source,
-                                       input_iface_vif_index);
-
-                       if (input_iface_vif_index < 1) {
-                               if (PIM_DEBUG_IGMP_TRACE) {
-                                       char source_str[INET_ADDRSTRLEN];
-                                       pim_inet4_dump("<source?>",
-                                               source->source_addr,
-                                               source_str, sizeof(source_str));
-                                       zlog_debug(
-                                               "%s %s: could not find input interface for source %s",
-                                               __FILE__, __func__, source_str);
-                               }
-                               source->source_channel_oil =
-                                       pim_channel_oil_add(pim, &sg, __func__);
-                       }
-
-                       else {
-                               /*
-                                * Protect IGMP against adding looped MFC
-                                * entries created by both source and receiver
-                                * attached to the same interface. See TODO
-                                * T22. Block only when the intf is non DR
-                                * DR must create upstream.
-                                */
-                               if ((input_iface_vif_index ==
-                                   pim_oif->mroute_vif_index) &&
-                                   !(PIM_I_am_DR(pim_oif))) {
-                                       /* ignore request for looped MFC entry
-                                        */
-                                       if (PIM_DEBUG_IGMP_TRACE) {
-                                               zlog_debug("%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
-                                                          __func__,
-                                                          &sg,
-                                                          source->source_group
-                                                          ->interface->name,
-                                                          input_iface_vif_index);
-                                       }
-                                       return;
-                               }
-
-                               source->source_channel_oil =
-                                       pim_channel_oil_add(pim, &sg, __func__);
-                               if (!source->source_channel_oil) {
-                                       if (PIM_DEBUG_IGMP_TRACE) {
-                                               zlog_debug("%s %s: could not create OIL for channel (S,G)=%pSG",
-                                                          __FILE__, __func__,
-                                                          &sg);
-                                       }
-                                       return;
-                               }
-                       }
-               }
-       }
-
-       if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
-               result = pim_channel_add_oif(source->source_channel_oil,
-                                            group->interface,
-                                            PIM_OIF_FLAG_PROTO_IGMP, __func__);
-               if (result) {
-                       if (PIM_DEBUG_MROUTE) {
-                               zlog_warn("%s: add_oif() failed with return=%d",
-                                         __func__, result);
-                       }
-                       return;
-               }
-       } else {
-               if (PIM_DEBUG_IGMP_TRACE)
-                       zlog_debug("%s: %pSG was received on %s interface but we are not DR for that interface",
-                                  __func__, &sg,
-                                  group->interface->name);
-
-               return;
-       }
-       /*
-         Feed IGMPv3-gathered local membership information into PIM
-         per-interface (S,G) state.
-        */
-       if (!pim_ifchannel_local_membership_add(group->interface, &sg,
-                                               false /*is_vxlan*/)) {
-               if (PIM_DEBUG_MROUTE)
-                       zlog_warn("%s: Failure to add local membership for %pSG",
-                                 __func__, &sg);
-
-               pim_channel_del_oif(source->source_channel_oil,
-                                   group->interface, PIM_OIF_FLAG_PROTO_IGMP,
-                                   __func__);
-               return;
-       }
-
-       IGMP_SOURCE_DO_FORWARDING(source->source_flags);
-}
-
-/*
-  igmp_source_forward_stop: stop fowarding, but keep the source
-  igmp_source_delete:       stop fowarding, and delete the source
- */
-void igmp_source_forward_stop(struct gm_source *source)
-{
-       struct gm_group *group;
-       pim_sgaddr sg;
-       int result;
-
-       memset(&sg, 0, sizeof(sg));
-       sg.src = source->source_addr;
-       sg.grp = source->source_group->group_addr;
-
-       if (PIM_DEBUG_IGMP_TRACE) {
-               zlog_debug("%s: (S,G)=%pSG oif=%s fwd=%d", __func__, &sg,
-                          source->source_group->interface->name,
-                          IGMP_SOURCE_TEST_FORWARDING(source->source_flags));
-       }
-
-       /* Prevent IGMP interface from removing multicast route multiple
-          times */
-       if (!IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
-               return;
-       }
-
-       group = source->source_group;
-
-       /*
-        It appears that in certain circumstances that
-        igmp_source_forward_stop is called when IGMP forwarding
-        was not enabled in oif_flags for this outgoing interface.
-        Possibly because of multiple calls. When that happens, we
-        enter the below if statement and this function returns early
-        which in turn triggers the calling function to assert.
-        Making the call to pim_channel_del_oif and ignoring the return code
-        fixes the issue without ill effect, similar to
-        pim_forward_stop below.
-       */
-       result = pim_channel_del_oif(source->source_channel_oil,
-                                    group->interface, PIM_OIF_FLAG_PROTO_IGMP,
-                                    __func__);
-       if (result) {
-               if (PIM_DEBUG_IGMP_TRACE)
-                       zlog_debug(
-                               "%s: pim_channel_del_oif() failed with return=%d",
-                               __func__, result);
-               return;
-       }
-
-       /*
-         Feed IGMPv3-gathered local membership information into PIM
-         per-interface (S,G) state.
-        */
-       pim_ifchannel_local_membership_del(group->interface, &sg);
-
-       IGMP_SOURCE_DONT_FORWARDING(source->source_flags);
-}
-#endif /* PIM_IPV == 4 */
-
 void pim_forward_start(struct pim_ifchannel *ch)
 {
        struct pim_upstream *up = ch->upstream;
@@ -825,7 +487,7 @@ void pim_forward_start(struct pim_ifchannel *ch)
                           ch->interface->name, &up->upstream_addr);
 
        if (PIM_IF_FLAG_TEST_PROTO_IGMP(ch->flags))
-               mask = PIM_OIF_FLAG_PROTO_IGMP;
+               mask = PIM_OIF_FLAG_PROTO_GM;
 
        if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags))
                mask |= PIM_OIF_FLAG_PROTO_PIM;