back to topotato report
topotato coverage report
Current view: top level - pimd - pim_oil.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 145 210 69.0 %
Date: 2023-02-24 14:41:08 Functions: 14 16 87.5 %

          Line data    Source code
       1             : /*
       2             :  * PIM for Quagga
       3             :  * Copyright (C) 2008  Everton da Silva Marques
       4             :  *
       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.
       9             :  *
      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.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License along
      16             :  * with this program; see the file COPYING; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      18             :  */
      19             : 
      20             : #include <zebra.h>
      21             : 
      22             : #include "log.h"
      23             : #include "memory.h"
      24             : #include "linklist.h"
      25             : #include "if.h"
      26             : #include "hash.h"
      27             : #include "jhash.h"
      28             : 
      29             : #include "pimd.h"
      30             : #include "pim_oil.h"
      31             : #include "pim_str.h"
      32             : #include "pim_iface.h"
      33             : #include "pim_time.h"
      34             : #include "pim_vxlan.h"
      35             : 
      36             : static void pim_channel_update_mute(struct channel_oil *c_oil);
      37             : 
      38           0 : char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
      39             : {
      40           0 :         char *out;
      41           0 :         struct interface *ifp;
      42           0 :         pim_sgaddr sg;
      43           0 :         int i;
      44             : 
      45           0 :         sg.src = *oil_origin(c_oil);
      46           0 :         sg.grp = *oil_mcastgrp(c_oil);
      47           0 :         ifp = pim_if_find_by_vif_index(c_oil->pim, *oil_parent(c_oil));
      48           0 :         snprintfrr(buf, size, "%pSG IIF: %s, OIFS: ", &sg,
      49             :                    ifp ? ifp->name : "(?)");
      50             : 
      51           0 :         out = buf + strlen(buf);
      52           0 :         for (i = 0; i < MAXVIFS; i++) {
      53           0 :                 if (oil_if_has(c_oil, i) != 0) {
      54           0 :                         ifp = pim_if_find_by_vif_index(c_oil->pim, i);
      55           0 :                         snprintf(out, buf + size - out, "%s ",
      56             :                                  ifp ? ifp->name : "(?)");
      57           0 :                         out += strlen(out);
      58             :                 }
      59             :         }
      60             : 
      61           0 :         return buf;
      62             : }
      63             : 
      64          25 : int pim_channel_oil_compare(const struct channel_oil *cc1,
      65             :                             const struct channel_oil *cc2)
      66             : {
      67          25 :         struct channel_oil *c1 = (struct channel_oil *)cc1;
      68          25 :         struct channel_oil *c2 = (struct channel_oil *)cc2;
      69          25 :         int rv;
      70             : 
      71          25 :         rv = pim_addr_cmp(*oil_mcastgrp(c1), *oil_mcastgrp(c2));
      72          25 :         if (rv)
      73             :                 return rv;
      74          11 :         rv = pim_addr_cmp(*oil_origin(c1), *oil_origin(c2));
      75          11 :         if (rv)
      76             :                 return rv;
      77             :         return 0;
      78             : }
      79             : 
      80          26 : void pim_oil_init(struct pim_instance *pim)
      81             : {
      82          26 :         rb_pim_oil_init(&pim->channel_oil_head);
      83          26 : }
      84             : 
      85          26 : void pim_oil_terminate(struct pim_instance *pim)
      86             : {
      87          26 :         struct channel_oil *c_oil;
      88             : 
      89          56 :         while ((c_oil = rb_pim_oil_pop(&pim->channel_oil_head)))
      90          30 :                 pim_channel_oil_free(c_oil);
      91             : 
      92          26 :         rb_pim_oil_fini(&pim->channel_oil_head);
      93          26 : }
      94             : 
      95          15 : void pim_channel_oil_free(struct channel_oil *c_oil)
      96             : {
      97           4 :         XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
      98           4 : }
      99             : 
     100          20 : struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
     101             :                                          pim_sgaddr *sg)
     102             : {
     103          20 :         struct channel_oil *c_oil = NULL;
     104          20 :         struct channel_oil lookup;
     105             : 
     106          20 :         *oil_mcastgrp(&lookup) = sg->grp;
     107          20 :         *oil_origin(&lookup) = sg->src;
     108             : 
     109          20 :         c_oil = rb_pim_oil_find(&pim->channel_oil_head, &lookup);
     110             : 
     111          20 :         return c_oil;
     112             : }
     113             : 
     114          20 : struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
     115             :                                         pim_sgaddr *sg, const char *name)
     116             : {
     117          20 :         struct channel_oil *c_oil;
     118             : 
     119          20 :         c_oil = pim_find_channel_oil(pim, sg);
     120          20 :         if (c_oil) {
     121           5 :                 ++c_oil->oil_ref_count;
     122             : 
     123           5 :                 if (!c_oil->up) {
     124             :                         /* channel might be present prior to upstream */
     125           5 :                         c_oil->up = pim_upstream_find(
     126             :                                         pim, sg);
     127             :                         /* if the upstream entry is being anchored to an
     128             :                          * already existing channel OIL we need to re-evaluate
     129             :                          * the "Mute" state on AA OIFs
     130             :                          */
     131           5 :                         pim_channel_update_mute(c_oil);
     132             :                 }
     133             : 
     134             :                 /* check if the IIF has changed
     135             :                  * XXX - is this really needed
     136             :                  */
     137           5 :                 pim_upstream_mroute_iif_update(c_oil, __func__);
     138             : 
     139           5 :                 if (PIM_DEBUG_MROUTE)
     140           0 :                         zlog_debug(
     141             :                                 "%s(%s): Existing oil for %pSG Ref Count: %d (Post Increment)",
     142             :                                 __func__, name, sg, c_oil->oil_ref_count);
     143           5 :                 return c_oil;
     144             :         }
     145             : 
     146          15 :         c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
     147             : 
     148          15 :         *oil_mcastgrp(c_oil) = sg->grp;
     149          15 :         *oil_origin(c_oil) = sg->src;
     150             : 
     151          15 :         *oil_parent(c_oil) = MAXVIFS;
     152          15 :         c_oil->oil_ref_count = 1;
     153          15 :         c_oil->installed = 0;
     154          15 :         c_oil->up = pim_upstream_find(pim, sg);
     155          15 :         c_oil->pim = pim;
     156             : 
     157          15 :         rb_pim_oil_add(&pim->channel_oil_head, c_oil);
     158             : 
     159          15 :         if (PIM_DEBUG_MROUTE)
     160           0 :                 zlog_debug("%s(%s): c_oil %pSG add", __func__, name, sg);
     161             : 
     162             :         return c_oil;
     163             : }
     164             : 
     165          16 : struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil,
     166             :                                         const char *name)
     167             : {
     168          16 :         if (PIM_DEBUG_MROUTE) {
     169           0 :                 pim_sgaddr sg = {.src = *oil_origin(c_oil),
     170           0 :                                  .grp = *oil_mcastgrp(c_oil)};
     171             : 
     172           0 :                 zlog_debug(
     173             :                         "%s(%s): Del oil for %pSG, Ref Count: %d (Predecrement)",
     174             :                         __func__, name, &sg, c_oil->oil_ref_count);
     175             :         }
     176          16 :         --c_oil->oil_ref_count;
     177             : 
     178          16 :         if (c_oil->oil_ref_count < 1) {
     179             :                 /*
     180             :                  * notice that listnode_delete() can't be moved
     181             :                  * into pim_channel_oil_free() because the later is
     182             :                  * called by list_delete_all_node()
     183             :                  */
     184          11 :                 c_oil->up = NULL;
     185          11 :                 rb_pim_oil_del(&c_oil->pim->channel_oil_head, c_oil);
     186             : 
     187          11 :                 pim_channel_oil_free(c_oil);
     188          11 :                 return NULL;
     189             :         }
     190             : 
     191             :         return c_oil;
     192             : }
     193             : 
     194          15 : void pim_channel_oil_upstream_deref(struct channel_oil *c_oil)
     195             : {
     196             :         /* The upstream entry associated with a channel_oil is abt to be
     197             :          * deleted. If the channel_oil is kept around because of other
     198             :          * references we need to remove upstream based states out of it.
     199             :          */
     200          15 :         c_oil = pim_channel_oil_del(c_oil, __func__);
     201          15 :         if (c_oil) {
     202             :                 /* note: here we assume that c_oil->up has already been
     203             :                  * cleared
     204             :                  */
     205           5 :                 pim_channel_update_mute(c_oil);
     206             :         }
     207          15 : }
     208             : 
     209          14 : int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
     210             :                         uint32_t proto_mask, const char *caller)
     211             : {
     212          14 :         struct pim_interface *pim_ifp;
     213             : 
     214          14 :         assert(channel_oil);
     215          14 :         assert(oif);
     216             : 
     217          14 :         pim_ifp = oif->info;
     218             : 
     219          14 :         assertf(pim_ifp->mroute_vif_index >= 0,
     220             :                 "trying to del OIF %s with VIF (%d)", oif->name,
     221             :                 pim_ifp->mroute_vif_index);
     222             : 
     223             :         /*
     224             :          * Don't do anything if we've been asked to remove a source
     225             :          * that is not actually on it.
     226             :          */
     227          14 :         if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
     228           5 :                 if (PIM_DEBUG_MROUTE) {
     229           0 :                         zlog_debug(
     230             :                                 "%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
     231             :                                 __FILE__, __func__, proto_mask,
     232             :                                 channel_oil
     233             :                                         ->oif_flags[pim_ifp->mroute_vif_index],
     234             :                                 oif->name, pim_ifp->mroute_vif_index,
     235             :                                 oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
     236             :                                 oil_origin(channel_oil),
     237             :                                 oil_mcastgrp(channel_oil));
     238             :                 }
     239           5 :                 return 0;
     240             :         }
     241             : 
     242           9 :         channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
     243             : 
     244           9 :         if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] &
     245             :                         PIM_OIF_FLAG_PROTO_ANY) {
     246           0 :                 if (PIM_DEBUG_MROUTE) {
     247           0 :                         zlog_debug(
     248             :                                 "%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
     249             :                                 __FILE__, __func__, oif->name,
     250             :                                 pim_ifp->mroute_vif_index,
     251             :                                 oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
     252             :                                 oil_origin(channel_oil),
     253             :                                 oil_mcastgrp(channel_oil));
     254             :                 }
     255           0 :                 return 0;
     256             :         }
     257             : 
     258           9 :         oil_if_set(channel_oil, pim_ifp->mroute_vif_index, 0);
     259             :         /* clear mute; will be re-evaluated when the OIF becomes valid again */
     260           9 :         channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~PIM_OIF_FLAG_MUTE;
     261             : 
     262           9 :         if (pim_upstream_mroute_add(channel_oil, __func__)) {
     263           0 :                 if (PIM_DEBUG_MROUTE) {
     264           0 :                         zlog_debug(
     265             :                                 "%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%pPAs,%pPAs)",
     266             :                                 __FILE__, __func__, oif->name,
     267             :                                 pim_ifp->mroute_vif_index,
     268             :                                 oil_origin(channel_oil),
     269             :                                 oil_mcastgrp(channel_oil));
     270             :                 }
     271           0 :                 return -1;
     272             :         }
     273             : 
     274           9 :         --channel_oil->oil_size;
     275             : 
     276           9 :         if (PIM_DEBUG_MROUTE) {
     277           0 :                 zlog_debug(
     278             :                         "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
     279             :                         __func__, caller, oil_origin(channel_oil),
     280             :                         oil_mcastgrp(channel_oil),
     281             :                         proto_mask,
     282             :                         *oil_parent(channel_oil), oif->name,
     283             :                         pim_ifp->mroute_vif_index);
     284             :         }
     285             : 
     286             :         return 0;
     287             : }
     288             : 
     289           1 : void pim_channel_del_inherited_oif(struct channel_oil *c_oil,
     290             :                 struct interface *oif, const char *caller)
     291             : {
     292           1 :         struct pim_upstream *up = c_oil->up;
     293             : 
     294           1 :         pim_channel_del_oif(c_oil, oif, PIM_OIF_FLAG_PROTO_STAR,
     295             :                         caller);
     296             : 
     297             :         /* if an inherited OIF is being removed join-desired can change
     298             :          * if the inherited OIL is now empty and KAT is running
     299             :          */
     300           2 :         if (up && !pim_addr_is_any(up->sg.src) &&
     301           1 :             pim_upstream_empty_inherited_olist(up))
     302           1 :                 pim_upstream_update_join_desired(up->pim, up);
     303           1 : }
     304             : 
     305          18 : static bool pim_channel_eval_oif_mute(struct channel_oil *c_oil,
     306             :                 struct pim_interface *pim_ifp)
     307             : {
     308          18 :         struct pim_interface *pim_reg_ifp;
     309          18 :         struct pim_interface *vxlan_ifp;
     310          18 :         bool do_mute = false;
     311          18 :         struct pim_instance *pim = c_oil->pim;
     312             : 
     313          18 :         if (!c_oil->up)
     314             :                 return do_mute;
     315             : 
     316          11 :         pim_reg_ifp = pim->regiface->info;
     317          11 :         if (pim_ifp == pim_reg_ifp) {
     318             :                 /* suppress pimreg in the OIL if the mroute is not supposed to
     319             :                  * trigger register encapsulated data
     320             :                  */
     321           5 :                 if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags))
     322           0 :                         do_mute = true;
     323             : 
     324           5 :                 return do_mute;
     325             :         }
     326             : 
     327           6 :         vxlan_ifp = pim_vxlan_get_term_ifp(pim);
     328           6 :         if (pim_ifp == vxlan_ifp) {
     329             :                 /* 1. vxlan termination device must never be added to the
     330             :                  * origination mroute (and that can actually happen because
     331             :                  * of XG inheritance from the termination mroute) otherwise
     332             :                  * traffic will end up looping.
     333             :                  * PS: This check has also been extended to non-orig mroutes
     334             :                  * that have a local SIP as such mroutes can move back and
     335             :                  * forth between orig<=>non-orig type.
     336             :                  * 2. vxlan termination device should be removed from the non-DF
     337             :                  * to prevent duplicates to the overlay rxer
     338             :                  */
     339           0 :                 if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) ||
     340           0 :                         PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags) ||
     341           0 :                         pim_vxlan_is_local_sip(c_oil->up))
     342             :                         do_mute = true;
     343             : 
     344           0 :                 return do_mute;
     345             :         }
     346             : 
     347           6 :         if (PIM_I_am_DualActive(pim_ifp)) {
     348           0 :                 struct pim_upstream *starup = c_oil->up->parent;
     349           0 :                 if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(c_oil->up->flags)
     350           0 :                     && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags)))
     351           0 :                         do_mute = true;
     352             : 
     353             :                 /* In case entry is (S,G), Negotiation happens at (*.G) */
     354           0 :                 if (starup
     355             : 
     356             :                     && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(starup->flags)
     357           0 :                     && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(starup->flags)))
     358           0 :                         do_mute = true;
     359           0 :                 return do_mute;
     360             :         }
     361             :         return do_mute;
     362             : }
     363             : 
     364          10 : void pim_channel_update_oif_mute(struct channel_oil *c_oil,
     365             :                 struct pim_interface *pim_ifp)
     366             : {
     367          10 :         bool old_mute;
     368          10 :         bool new_mute;
     369             : 
     370             :         /* If pim_ifp is not a part of the OIL there is nothing to do */
     371          10 :         if (!oil_if_has(c_oil, pim_ifp->mroute_vif_index))
     372             :                 return;
     373             : 
     374           2 :         old_mute = !!(c_oil->oif_flags[pim_ifp->mroute_vif_index] &
     375             :                         PIM_OIF_FLAG_MUTE);
     376           2 :         new_mute = pim_channel_eval_oif_mute(c_oil, pim_ifp);
     377           2 :         if (old_mute == new_mute)
     378             :                 return;
     379             : 
     380           0 :         if (new_mute)
     381           0 :                 c_oil->oif_flags[pim_ifp->mroute_vif_index] |=
     382             :                         PIM_OIF_FLAG_MUTE;
     383             :         else
     384           0 :                 c_oil->oif_flags[pim_ifp->mroute_vif_index] &=
     385             :                         ~PIM_OIF_FLAG_MUTE;
     386             : 
     387           0 :         pim_upstream_mroute_add(c_oil, __func__);
     388             : }
     389             : 
     390             : /* pim_upstream has been set or cleared on the c_oil. re-eval mute state
     391             :  * on all existing OIFs
     392             :  */
     393          10 : static void pim_channel_update_mute(struct channel_oil *c_oil)
     394             : {
     395          10 :         struct pim_interface *pim_reg_ifp;
     396          10 :         struct pim_interface *vxlan_ifp;
     397             : 
     398          10 :         if (c_oil->pim->regiface) {
     399          10 :                 pim_reg_ifp = c_oil->pim->regiface->info;
     400          10 :                 if (pim_reg_ifp)
     401          10 :                         pim_channel_update_oif_mute(c_oil, pim_reg_ifp);
     402             :         }
     403          10 :         vxlan_ifp = pim_vxlan_get_term_ifp(c_oil->pim);
     404          10 :         if (vxlan_ifp)
     405           0 :                 pim_channel_update_oif_mute(c_oil, vxlan_ifp);
     406          10 : }
     407             : 
     408          32 : int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
     409             :                         uint32_t proto_mask, const char *caller)
     410             : {
     411          32 :         struct pim_interface *pim_ifp;
     412          32 :         int old_ttl;
     413             : 
     414             :         /*
     415             :          * If we've gotten here we've gone bad, but let's
     416             :          * not take down pim
     417             :          */
     418          32 :         if (!channel_oil) {
     419           0 :                 zlog_warn("Attempt to Add OIF for non-existent channel oil");
     420           0 :                 return -1;
     421             :         }
     422             : 
     423          32 :         pim_ifp = oif->info;
     424             : 
     425          32 :         assertf(pim_ifp->mroute_vif_index >= 0,
     426             :                 "trying to add OIF %s with VIF (%d)", oif->name,
     427             :                 pim_ifp->mroute_vif_index);
     428             : 
     429             :         /* Prevent single protocol from subscribing same interface to
     430             :            channel (S,G) multiple times */
     431          32 :         if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
     432          16 :                 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
     433             : 
     434          16 :                 if (PIM_DEBUG_MROUTE) {
     435           0 :                         zlog_debug(
     436             :                                 "%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
     437             :                                 __FILE__, __func__, proto_mask, oif->name,
     438             :                                 pim_ifp->mroute_vif_index,
     439             :                                 oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
     440             :                                 oil_origin(channel_oil),
     441             :                                 oil_mcastgrp(channel_oil));
     442             :                 }
     443          16 :                 return -3;
     444             :         }
     445             : 
     446             :         /* Allow other protocol to request subscription of same interface to
     447             :          * channel (S,G), we need to note this information
     448             :          */
     449          16 :         if (channel_oil->oif_flags[pim_ifp->mroute_vif_index]
     450          16 :             & PIM_OIF_FLAG_PROTO_ANY) {
     451             : 
     452             :                 /* Updating time here is not required as this time has to
     453             :                  * indicate when the interface is added
     454             :                  */
     455             : 
     456           0 :                 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
     457             :                 /* Check the OIF really exists before returning, and only log
     458             :                    warning otherwise */
     459           0 :                 if (oil_if_has(channel_oil, pim_ifp->mroute_vif_index) < 1) {
     460           0 :                         zlog_warn(
     461             :                                 "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
     462             :                                 __FILE__, __func__, proto_mask, oif->name,
     463             :                                 pim_ifp->mroute_vif_index,
     464             :                                 oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
     465             :                                 oil_origin(channel_oil),
     466             :                                 oil_mcastgrp(channel_oil));
     467             :                 }
     468             : 
     469           0 :                 if (PIM_DEBUG_MROUTE) {
     470           0 :                         zlog_debug(
     471             :                                 "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u OIF=%s vif_index=%d added to 0x%x",
     472             :                                 __func__, caller, oil_origin(channel_oil),
     473             :                                 oil_mcastgrp(channel_oil),
     474             :                                 proto_mask, oif->name,
     475             :                                 pim_ifp->mroute_vif_index,
     476             :                                 channel_oil
     477             :                                         ->oif_flags[pim_ifp->mroute_vif_index]);
     478             :                 }
     479           0 :                 return 0;
     480             :         }
     481             : 
     482          16 :         old_ttl = oil_if_has(channel_oil, pim_ifp->mroute_vif_index);
     483             : 
     484          16 :         if (old_ttl > 0) {
     485           0 :                 if (PIM_DEBUG_MROUTE) {
     486           0 :                         zlog_debug(
     487             :                                 "%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%pPAs,%pPAs)",
     488             :                                 __FILE__, __func__, oif->name,
     489             :                                 pim_ifp->mroute_vif_index,
     490             :                                 oil_origin(channel_oil),
     491             :                                 oil_mcastgrp(channel_oil));
     492             :                 }
     493           0 :                 return -4;
     494             :         }
     495             : 
     496          16 :         oil_if_set(channel_oil, pim_ifp->mroute_vif_index, PIM_MROUTE_MIN_TTL);
     497             : 
     498             :         /* Some OIFs are held in a muted state i.e. the PIM state machine
     499             :          * decided to include the OIF but additional status check such as
     500             :          * MLAG DF role prevent it from being activated for traffic
     501             :          * forwarding.
     502             :          */
     503          16 :         if (pim_channel_eval_oif_mute(channel_oil, pim_ifp))
     504           0 :                 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |=
     505             :                         PIM_OIF_FLAG_MUTE;
     506             :         else
     507          16 :                 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &=
     508             :                         ~PIM_OIF_FLAG_MUTE;
     509             : 
     510             :         /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not
     511             :          * valid to get installed in kernel.
     512             :          */
     513          16 :         if (*oil_parent(channel_oil) != MAXVIFS) {
     514           7 :                 if (pim_upstream_mroute_add(channel_oil, __func__)) {
     515           0 :                         if (PIM_DEBUG_MROUTE) {
     516           0 :                                 zlog_debug(
     517             :                                         "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%pPAs,%pPAs)",
     518             :                                         __FILE__, __func__, oif->name,
     519             :                                         pim_ifp->mroute_vif_index,
     520             :                                         oil_origin(channel_oil),
     521             :                                         oil_mcastgrp(channel_oil));
     522             :                         }
     523             : 
     524           0 :                         oil_if_set(channel_oil, pim_ifp->mroute_vif_index,
     525             :                                    old_ttl);
     526           0 :                         return -5;
     527             :                 }
     528             :         }
     529             : 
     530          32 :         channel_oil->oif_creation[pim_ifp->mroute_vif_index] =
     531          16 :                 pim_time_monotonic_sec();
     532          16 :         ++channel_oil->oil_size;
     533          16 :         channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
     534             : 
     535          16 :         if (PIM_DEBUG_MROUTE) {
     536           0 :                 zlog_debug(
     537             :                         "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u OIF=%s vif_index=%d: DONE",
     538             :                         __func__, caller, oil_origin(channel_oil),
     539             :                         oil_mcastgrp(channel_oil),
     540             :                         proto_mask,
     541             :                         oif->name, pim_ifp->mroute_vif_index);
     542             :         }
     543             : 
     544             :         return 0;
     545             : }
     546             : 
     547          67 : int pim_channel_oil_empty(struct channel_oil *c_oil)
     548             : {
     549          67 :         static struct channel_oil null_oil;
     550             : 
     551          67 :         if (!c_oil)
     552             :                 return 1;
     553             : 
     554             :         /* exclude pimreg from the OIL when checking if the inherited_oil is
     555             :          * non-NULL.
     556             :          * pimreg device (in all vrfs) uses a vifi of
     557             :          * 0 (PIM_OIF_PIM_REGISTER_VIF) so we simply mfcc_ttls[0] */
     558          60 :         if (oil_if_has(c_oil, 0))
     559           6 :                 oil_if_set(&null_oil, 0, 1);
     560             :         else
     561          54 :                 oil_if_set(&null_oil, 0, 0);
     562             : 
     563          60 :         return !oil_if_cmp(&c_oil->oil, &null_oil.oil);
     564             : }

Generated by: LCOV version v1.16-topotato