back to topotato report
topotato coverage report
Current view: top level - pimd - pim_iface.c (source / functions) Hit Total Coverage
Test: test_pim6_prune_propagate.py::PIM6PrunePropagate Lines: 411 601 68.4 %
Date: 2023-02-24 18:39:23 Functions: 36 53 67.9 %

          Line data    Source code
       1             : /*
       2             :  * PIM for Quagga
       3             :  * Copyright (C) 2008  Everton da Silva Marques
       4             :  * This program is free software; you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation; either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful, but
      10             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             :  * General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License along
      15             :  * with this program; see the file COPYING; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      17             :  */
      18             : 
      19             : #include <zebra.h>
      20             : 
      21             : #include "if.h"
      22             : #include "log.h"
      23             : #include "vty.h"
      24             : #include "memory.h"
      25             : #include "prefix.h"
      26             : #include "vrf.h"
      27             : #include "linklist.h"
      28             : #include "plist.h"
      29             : #include "hash.h"
      30             : #include "ferr.h"
      31             : #include "network.h"
      32             : 
      33             : #include "pimd.h"
      34             : #include "pim_instance.h"
      35             : #include "pim_zebra.h"
      36             : #include "pim_iface.h"
      37             : #include "pim_igmp.h"
      38             : #include "pim_mroute.h"
      39             : #include "pim_oil.h"
      40             : #include "pim_str.h"
      41             : #include "pim_pim.h"
      42             : #include "pim_neighbor.h"
      43             : #include "pim_ifchannel.h"
      44             : #include "pim_sock.h"
      45             : #include "pim_time.h"
      46             : #include "pim_ssmpingd.h"
      47             : #include "pim_rp.h"
      48             : #include "pim_nht.h"
      49             : #include "pim_jp_agg.h"
      50             : #include "pim_igmp_join.h"
      51             : #include "pim_vxlan.h"
      52             : 
      53             : #include "pim6_mld.h"
      54             : 
      55             : #if PIM_IPV == 4
      56             : static void pim_if_igmp_join_del_all(struct interface *ifp);
      57             : static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
      58             :                           struct in_addr group_addr, struct in_addr source_addr,
      59             :                           struct pim_interface *pim_ifp);
      60             : #endif
      61             : 
      62           4 : void pim_if_init(struct pim_instance *pim)
      63             : {
      64           4 :         int i;
      65             : 
      66        1028 :         for (i = 0; i < MAXVIFS; i++)
      67        1024 :                 pim->iface_vif_index[i] = 0;
      68           4 : }
      69             : 
      70           4 : void pim_if_terminate(struct pim_instance *pim)
      71             : {
      72           4 :         struct interface *ifp;
      73             : 
      74          24 :         FOR_ALL_INTERFACES (pim->vrf, ifp) {
      75          16 :                 struct pim_interface *pim_ifp = ifp->info;
      76             : 
      77          16 :                 if (!pim_ifp)
      78           4 :                         continue;
      79             : 
      80          12 :                 pim_if_delete(ifp);
      81             :         }
      82           4 :         return;
      83             : }
      84             : 
      85           2 : static void pim_sec_addr_free(struct pim_secondary_addr *sec_addr)
      86             : {
      87           2 :         XFREE(MTYPE_PIM_SEC_ADDR, sec_addr);
      88           2 : }
      89             : 
      90             : __attribute__((unused))
      91           0 : static int pim_sec_addr_comp(const void *p1, const void *p2)
      92             : {
      93           0 :         const struct pim_secondary_addr *sec1 = p1;
      94           0 :         const struct pim_secondary_addr *sec2 = p2;
      95             : 
      96           0 :         if (sec1->addr.family == AF_INET && sec2->addr.family == AF_INET6)
      97             :                 return -1;
      98             : 
      99           0 :         if (sec1->addr.family == AF_INET6 && sec2->addr.family == AF_INET)
     100             :                 return 1;
     101             : 
     102           0 :         if (sec1->addr.family == AF_INET) {
     103           0 :                 if (ntohl(sec1->addr.u.prefix4.s_addr)
     104           0 :                     < ntohl(sec2->addr.u.prefix4.s_addr))
     105             :                         return -1;
     106             : 
     107           0 :                 if (ntohl(sec1->addr.u.prefix4.s_addr)
     108           0 :                     > ntohl(sec2->addr.u.prefix4.s_addr))
     109           0 :                         return 1;
     110             :         } else {
     111           0 :                 return memcmp(&sec1->addr.u.prefix6, &sec2->addr.u.prefix6,
     112             :                               sizeof(struct in6_addr));
     113             :         }
     114             : 
     115             :         return 0;
     116             : }
     117             : 
     118          12 : struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,
     119             :                                  bool ispimreg, bool is_vxlan_term)
     120             : {
     121          12 :         struct pim_interface *pim_ifp;
     122             : 
     123          12 :         assert(ifp);
     124          12 :         assert(!ifp->info);
     125             : 
     126          12 :         pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
     127             : 
     128          12 :         pim_ifp->pim = ifp->vrf->info;
     129          12 :         pim_ifp->mroute_vif_index = -1;
     130             : 
     131          12 :         pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
     132          12 :         pim_ifp->mld_version = MLD_DEFAULT_VERSION;
     133          12 :         pim_ifp->gm_default_robustness_variable =
     134             :                 GM_DEFAULT_ROBUSTNESS_VARIABLE;
     135          12 :         pim_ifp->gm_default_query_interval = GM_GENERAL_QUERY_INTERVAL;
     136          12 :         pim_ifp->gm_query_max_response_time_dsec =
     137             :                 GM_QUERY_MAX_RESPONSE_TIME_DSEC;
     138          12 :         pim_ifp->gm_specific_query_max_response_time_dsec =
     139             :                 GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
     140          12 :         pim_ifp->gm_last_member_query_count = GM_DEFAULT_ROBUSTNESS_VARIABLE;
     141             : 
     142             :         /* BSM config on interface: true by default */
     143          12 :         pim_ifp->bsm_enable = true;
     144          12 :         pim_ifp->ucast_bsm_accept = true;
     145          12 :         pim_ifp->am_i_dr = false;
     146             : 
     147             :         /*
     148             :           RFC 3376: 8.3. Query Response Interval
     149             :           The number of seconds represented by the [Query Response Interval]
     150             :           must be less than the [Query Interval].
     151             :          */
     152          12 :         assert(pim_ifp->gm_query_max_response_time_dsec <
     153             :                pim_ifp->gm_default_query_interval);
     154             : 
     155          12 :         pim_ifp->pim_enable = pim;
     156          12 :         pim_ifp->pim_passive_enable = false;
     157          12 :         pim_ifp->gm_enable = gm;
     158             : 
     159          12 :         pim_ifp->gm_join_list = NULL;
     160          12 :         pim_ifp->pim_neighbor_list = NULL;
     161          12 :         pim_ifp->upstream_switch_list = NULL;
     162          12 :         pim_ifp->pim_generation_id = 0;
     163             : 
     164             :         /* list of struct gm_sock */
     165          12 :         pim_igmp_if_init(pim_ifp, ifp);
     166             : 
     167             :         /* list of struct pim_neighbor */
     168          12 :         pim_ifp->pim_neighbor_list = list_new();
     169          12 :         pim_ifp->pim_neighbor_list->del = (void (*)(void *))pim_neighbor_free;
     170             : 
     171          12 :         pim_ifp->upstream_switch_list = list_new();
     172          12 :         pim_ifp->upstream_switch_list->del =
     173             :                 (void (*)(void *))pim_jp_agg_group_list_free;
     174          12 :         pim_ifp->upstream_switch_list->cmp = pim_jp_agg_group_list_cmp;
     175             : 
     176          12 :         pim_ifp->sec_addr_list = list_new();
     177          12 :         pim_ifp->sec_addr_list->del = (void (*)(void *))pim_sec_addr_free;
     178          12 :         pim_ifp->sec_addr_list->cmp =
     179             :                 (int (*)(void *, void *))pim_sec_addr_comp;
     180             : 
     181          12 :         pim_ifp->activeactive = false;
     182             : 
     183          12 :         RB_INIT(pim_ifchannel_rb, &pim_ifp->ifchannel_rb);
     184             : 
     185          12 :         ifp->info = pim_ifp;
     186             : 
     187          12 :         pim_sock_reset(ifp);
     188             : 
     189          12 :         pim_if_add_vif(ifp, ispimreg, is_vxlan_term);
     190          12 :         pim_ifp->pim->mcast_if_count++;
     191             : 
     192          12 :         return pim_ifp;
     193             : }
     194             : 
     195          12 : void pim_if_delete(struct interface *ifp)
     196             : {
     197          12 :         struct pim_interface *pim_ifp;
     198             : 
     199          12 :         assert(ifp);
     200          12 :         pim_ifp = ifp->info;
     201          12 :         assert(pim_ifp);
     202             : 
     203          12 :         pim_ifp->pim->mcast_if_count--;
     204             : #if PIM_IPV == 4
     205             :         if (pim_ifp->gm_join_list) {
     206             :                 pim_if_igmp_join_del_all(ifp);
     207             :         }
     208             : #endif
     209             : 
     210          12 :         pim_ifchannel_delete_all(ifp);
     211             : #if PIM_IPV == 4
     212             :         igmp_sock_delete_all(ifp);
     213             : #endif
     214          12 :         if (pim_ifp->pim_sock_fd >= 0)
     215           8 :                 pim_sock_delete(ifp, "Interface removed from configuration");
     216             : 
     217          12 :         pim_if_del_vif(ifp);
     218             : 
     219          12 :         pim_igmp_if_fini(pim_ifp);
     220             : 
     221          12 :         list_delete(&pim_ifp->pim_neighbor_list);
     222          12 :         list_delete(&pim_ifp->upstream_switch_list);
     223          12 :         list_delete(&pim_ifp->sec_addr_list);
     224             : 
     225          12 :         if (pim_ifp->bfd_config.profile)
     226           0 :                 XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
     227             : 
     228          12 :         XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
     229          12 :         XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
     230             : 
     231          12 :         ifp->info = NULL;
     232          12 : }
     233             : 
     234          21 : void pim_if_update_could_assert(struct interface *ifp)
     235             : {
     236          21 :         struct pim_interface *pim_ifp;
     237          21 :         struct pim_ifchannel *ch;
     238             : 
     239          21 :         pim_ifp = ifp->info;
     240          21 :         assert(pim_ifp);
     241             : 
     242          42 :         RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
     243           0 :                 pim_ifchannel_update_could_assert(ch);
     244             :         }
     245          21 : }
     246             : 
     247          10 : static void pim_if_update_my_assert_metric(struct interface *ifp)
     248             : {
     249          10 :         struct pim_interface *pim_ifp;
     250          10 :         struct pim_ifchannel *ch;
     251             : 
     252          10 :         pim_ifp = ifp->info;
     253          10 :         assert(pim_ifp);
     254             : 
     255          20 :         RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
     256           0 :                 pim_ifchannel_update_my_assert_metric(ch);
     257             :         }
     258          10 : }
     259             : 
     260          10 : static void pim_addr_change(struct interface *ifp)
     261             : {
     262          10 :         struct pim_interface *pim_ifp;
     263             : 
     264          10 :         pim_ifp = ifp->info;
     265          10 :         assert(pim_ifp);
     266             : 
     267          10 :         pim_if_dr_election(ifp); /* router's own DR Priority (addr) changes --
     268             :                                     Done TODO T30 */
     269          10 :         pim_if_update_join_desired(pim_ifp); /* depends on DR */
     270          10 :         pim_if_update_could_assert(ifp);     /* depends on DR */
     271          10 :         pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
     272          10 :         pim_if_update_assert_tracking_desired(
     273             :                 ifp); /* depends on DR, join_desired */
     274             : 
     275             :         /*
     276             :           RFC 4601: 4.3.1.  Sending Hello Messages
     277             : 
     278             :           1) Before an interface goes down or changes primary IP address, a
     279             :           Hello message with a zero HoldTime should be sent immediately
     280             :           (with the old IP address if the IP address changed).
     281             :           -- Done at the caller of the function as new ip already updated here
     282             : 
     283             :           2) After an interface has changed its IP address, it MUST send a
     284             :           Hello message with its new IP address.
     285             :           -- DONE below
     286             : 
     287             :           3) If an interface changes one of its secondary IP addresses, a
     288             :           Hello message with an updated Address_List option and a non-zero
     289             :           HoldTime should be sent immediately.
     290             :           -- FIXME See TODO T31
     291             :          */
     292          10 :         PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags);
     293          10 :         if (pim_ifp->pim_sock_fd < 0)
     294             :                 return;
     295           0 :         pim_hello_restart_now(ifp); /* send hello and restart timer */
     296             : }
     297             : 
     298          24 : static int detect_primary_address_change(struct interface *ifp,
     299             :                                          int force_prim_as_any,
     300             :                                          const char *caller)
     301             : {
     302          24 :         struct pim_interface *pim_ifp = ifp->info;
     303          24 :         pim_addr new_prim_addr;
     304          24 :         int changed;
     305             : 
     306          24 :         if (force_prim_as_any)
     307           0 :                 new_prim_addr = PIMADDR_ANY;
     308             :         else
     309          24 :                 new_prim_addr = pim_find_primary_addr(ifp);
     310             : 
     311          24 :         changed = pim_addr_cmp(new_prim_addr, pim_ifp->primary_address);
     312             : 
     313          24 :         if (PIM_DEBUG_ZEBRA)
     314           0 :                 zlog_debug("%s: old=%pPA new=%pPA on interface %s: %s",
     315             :                            __func__, &pim_ifp->primary_address, &new_prim_addr,
     316             :                            ifp->name, changed ? "changed" : "unchanged");
     317             : 
     318          24 :         if (changed) {
     319             :                 /* Before updating pim_ifp send Hello time with 0 hold time */
     320           8 :                 if (pim_ifp->pim_enable) {
     321           8 :                         pim_hello_send(ifp, 0 /* zero-sec holdtime */);
     322             :                 }
     323           8 :                 pim_ifp->primary_address = new_prim_addr;
     324             :         }
     325             : 
     326          24 :         return changed;
     327             : }
     328             : 
     329             : static struct pim_secondary_addr *
     330           8 : pim_sec_addr_find(struct pim_interface *pim_ifp, struct prefix *addr)
     331             : {
     332           8 :         struct pim_secondary_addr *sec_addr;
     333           8 :         struct listnode *node;
     334             : 
     335          16 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
     336           6 :                 if (prefix_cmp(&sec_addr->addr, addr) == 0) {
     337           6 :                         return sec_addr;
     338             :                 }
     339             :         }
     340             : 
     341             :         return NULL;
     342             : }
     343             : 
     344           0 : static void pim_sec_addr_del(struct pim_interface *pim_ifp,
     345             :                              struct pim_secondary_addr *sec_addr)
     346             : {
     347           0 :         listnode_delete(pim_ifp->sec_addr_list, sec_addr);
     348           0 :         pim_sec_addr_free(sec_addr);
     349           0 : }
     350             : 
     351           8 : static int pim_sec_addr_add(struct pim_interface *pim_ifp, struct prefix *addr)
     352             : {
     353           8 :         int changed = 0;
     354           8 :         struct pim_secondary_addr *sec_addr;
     355             : 
     356           8 :         sec_addr = pim_sec_addr_find(pim_ifp, addr);
     357           8 :         if (sec_addr) {
     358           6 :                 sec_addr->flags &= ~PIM_SEC_ADDRF_STALE;
     359           6 :                 return changed;
     360             :         }
     361             : 
     362           2 :         sec_addr = XCALLOC(MTYPE_PIM_SEC_ADDR, sizeof(*sec_addr));
     363             : 
     364           2 :         changed = 1;
     365           2 :         sec_addr->addr = *addr;
     366           2 :         listnode_add_sort(pim_ifp->sec_addr_list, sec_addr);
     367             : 
     368           2 :         return changed;
     369             : }
     370             : 
     371           0 : static int pim_sec_addr_del_all(struct pim_interface *pim_ifp)
     372             : {
     373           0 :         int changed = 0;
     374             : 
     375           0 :         if (!list_isempty(pim_ifp->sec_addr_list)) {
     376           0 :                 changed = 1;
     377             :                 /* remove all nodes and free up the list itself */
     378           0 :                 list_delete_all_node(pim_ifp->sec_addr_list);
     379             :         }
     380             : 
     381           0 :         return changed;
     382             : }
     383             : 
     384          24 : static int pim_sec_addr_update(struct interface *ifp)
     385             : {
     386          24 :         struct pim_interface *pim_ifp = ifp->info;
     387          24 :         struct connected *ifc;
     388          24 :         struct listnode *node;
     389          24 :         struct listnode *nextnode;
     390          24 :         struct pim_secondary_addr *sec_addr;
     391          24 :         int changed = 0;
     392             : 
     393          54 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->sec_addr_list, node, sec_addr)) {
     394           6 :                 sec_addr->flags |= PIM_SEC_ADDRF_STALE;
     395             :         }
     396             : 
     397          88 :         for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
     398          40 :                 pim_addr addr = pim_addr_from_prefix(ifc->address);
     399             : 
     400          40 :                 if (pim_addr_is_any(addr))
     401          24 :                         continue;
     402             : 
     403          16 :                 if (!pim_addr_cmp(addr, pim_ifp->primary_address)) {
     404             :                         /* don't add the primary address into the secondary
     405             :                          * address list */
     406           8 :                         continue;
     407             :                 }
     408             : 
     409           8 :                 if (pim_sec_addr_add(pim_ifp, ifc->address)) {
     410          40 :                         changed = 1;
     411             :                 }
     412             :         }
     413             : 
     414             :         /* Drop stale entries */
     415          56 :         for (ALL_LIST_ELEMENTS(pim_ifp->sec_addr_list, node, nextnode,
     416             :                                sec_addr)) {
     417           8 :                 if (sec_addr->flags & PIM_SEC_ADDRF_STALE) {
     418           0 :                         pim_sec_addr_del(pim_ifp, sec_addr);
     419           0 :                         changed = 1;
     420             :                 }
     421             :         }
     422             : 
     423          24 :         return changed;
     424             : }
     425             : 
     426          24 : static int detect_secondary_address_change(struct interface *ifp,
     427             :                                            int force_prim_as_any,
     428             :                                            const char *caller)
     429             : {
     430          24 :         struct pim_interface *pim_ifp = ifp->info;
     431          24 :         int changed = 0;
     432             : 
     433          24 :         if (force_prim_as_any) {
     434             :                 /* if primary address is being forced to zero just flush the
     435             :                  * secondary address list */
     436           0 :                 changed = pim_sec_addr_del_all(pim_ifp);
     437             :         } else {
     438             :                 /* re-evaluate the secondary address list */
     439          24 :                 changed = pim_sec_addr_update(ifp);
     440             :         }
     441             : 
     442          24 :         return changed;
     443             : }
     444             : 
     445          24 : static void detect_address_change(struct interface *ifp, int force_prim_as_any,
     446             :                                   const char *caller)
     447             : {
     448          24 :         int changed = 0;
     449          24 :         struct pim_interface *pim_ifp;
     450             : 
     451          24 :         pim_ifp = ifp->info;
     452          24 :         if (!pim_ifp)
     453             :                 return;
     454             : 
     455          24 :         if (detect_primary_address_change(ifp, force_prim_as_any, caller)) {
     456           8 :                 changed = 1;
     457             :         }
     458             : 
     459          24 :         if (detect_secondary_address_change(ifp, force_prim_as_any, caller)) {
     460             :                 changed = 1;
     461             :         }
     462             : 
     463             : 
     464          22 :         if (changed) {
     465          10 :                 if (!pim_ifp->pim_enable) {
     466             :                         return;
     467             :                 }
     468             : 
     469          10 :                 pim_addr_change(ifp);
     470             :         }
     471             : 
     472             :         /* XXX: if we have unnumbered interfaces we need to run detect address
     473             :          * address change on all of them when the lo address changes */
     474             : }
     475             : 
     476           0 : int pim_update_source_set(struct interface *ifp, pim_addr source)
     477             : {
     478           0 :         struct pim_interface *pim_ifp = ifp->info;
     479             : 
     480           0 :         if (!pim_ifp) {
     481             :                 return PIM_IFACE_NOT_FOUND;
     482             :         }
     483             : 
     484           0 :         if (!pim_addr_cmp(pim_ifp->update_source, source)) {
     485             :                 return PIM_UPDATE_SOURCE_DUP;
     486             :         }
     487             : 
     488           0 :         pim_ifp->update_source = source;
     489           0 :         detect_address_change(ifp, 0 /* force_prim_as_any */, __func__);
     490             : 
     491           0 :         return PIM_SUCCESS;
     492             : }
     493             : 
     494          48 : void pim_if_addr_add(struct connected *ifc)
     495             : {
     496          48 :         struct pim_interface *pim_ifp;
     497          48 :         struct interface *ifp;
     498          48 :         bool vxlan_term;
     499             : 
     500          48 :         assert(ifc);
     501             : 
     502          48 :         ifp = ifc->ifp;
     503          48 :         assert(ifp);
     504          48 :         pim_ifp = ifp->info;
     505          48 :         if (!pim_ifp)
     506             :                 return;
     507             : 
     508          36 :         if (!if_is_operative(ifp))
     509             :                 return;
     510             : 
     511          24 :         if (PIM_DEBUG_ZEBRA)
     512           0 :                 zlog_debug("%s: %s ifindex=%d connected IP address %pFX %s",
     513             :                            __func__, ifp->name, ifp->ifindex, ifc->address,
     514             :                            CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
     515             :                                    ? "secondary"
     516             :                                    : "primary");
     517             : #if PIM_IPV != 4
     518          24 :         if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6) ||
     519          16 :             IN6_IS_ADDR_LOOPBACK(&ifc->address->u.prefix6)) {
     520           8 :                 if (IN6_IS_ADDR_UNSPECIFIED(&pim_ifp->ll_lowest))
     521           8 :                         pim_ifp->ll_lowest = ifc->address->u.prefix6;
     522           0 :                 else if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
     523             :                                        &pim_ifp->ll_lowest) < 0)
     524           0 :                         pim_ifp->ll_lowest = ifc->address->u.prefix6;
     525             : 
     526           8 :                 if (IPV6_ADDR_CMP(&ifc->address->u.prefix6,
     527             :                                   &pim_ifp->ll_highest) > 0)
     528           8 :                         pim_ifp->ll_highest = ifc->address->u.prefix6;
     529             : 
     530           8 :                 if (PIM_DEBUG_ZEBRA)
     531           0 :                         zlog_debug(
     532             :                                 "%s: new link-local %pI6, lowest now %pI6, highest %pI6",
     533             :                                 ifc->ifp->name, &ifc->address->u.prefix6,
     534             :                                 &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
     535             :         }
     536             : #endif
     537             : 
     538          24 :         detect_address_change(ifp, 0, __func__);
     539             : 
     540             :         // if (ifc->address->family != AF_INET)
     541             :         //  return;
     542             : 
     543             : #if PIM_IPV == 4
     544             :         struct in_addr ifaddr = ifc->address->u.prefix4;
     545             : 
     546             :         if (pim_ifp->gm_enable) {
     547             :                 struct gm_sock *igmp;
     548             : 
     549             :                 /* lookup IGMP socket */
     550             :                 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
     551             :                                                    ifaddr);
     552             :                 if (!igmp) {
     553             :                         /* if addr new, add IGMP socket */
     554             :                         if (ifc->address->family == AF_INET)
     555             :                                 pim_igmp_sock_add(pim_ifp->gm_socket_list,
     556             :                                                   ifaddr, ifp, false);
     557             :                 } else if (igmp->mtrace_only) {
     558             :                         igmp_sock_delete(igmp);
     559             :                         pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp,
     560             :                                           false);
     561             :                 }
     562             : 
     563             :                 /* Replay Static IGMP groups */
     564             :                 if (pim_ifp->gm_join_list) {
     565             :                         struct listnode *node;
     566             :                         struct listnode *nextnode;
     567             :                         struct gm_join *ij;
     568             :                         int join_fd;
     569             : 
     570             :                         for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node,
     571             :                                                nextnode, ij)) {
     572             :                                 /* Close socket and reopen with Source and Group
     573             :                                  */
     574             :                                 close(ij->sock_fd);
     575             :                                 join_fd = igmp_join_sock(
     576             :                                         ifp->name, ifp->ifindex, ij->group_addr,
     577             :                                         ij->source_addr, pim_ifp);
     578             :                                 if (join_fd < 0) {
     579             :                                         char group_str[INET_ADDRSTRLEN];
     580             :                                         char source_str[INET_ADDRSTRLEN];
     581             :                                         pim_inet4_dump("<grp?>", ij->group_addr,
     582             :                                                        group_str,
     583             :                                                        sizeof(group_str));
     584             :                                         pim_inet4_dump(
     585             :                                                 "<src?>", ij->source_addr,
     586             :                                                 source_str, sizeof(source_str));
     587             :                                         zlog_warn(
     588             :                                                 "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
     589             :                                                 __func__, group_str, source_str,
     590             :                                                 ifp->name);
     591             :                                         /* warning only */
     592             :                                 } else
     593             :                                         ij->sock_fd = join_fd;
     594             :                         }
     595             :                 }
     596             :         } /* igmp */
     597             :         else {
     598             :                 struct gm_sock *igmp;
     599             : 
     600             :                 /* lookup IGMP socket */
     601             :                 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list,
     602             :                                                    ifaddr);
     603             :                 if (ifc->address->family == AF_INET) {
     604             :                         if (igmp)
     605             :                                 igmp_sock_delete(igmp);
     606             :                         /* if addr new, add IGMP socket */
     607             :                         pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp,
     608             :                                           true);
     609             :                 }
     610             :         } /* igmp mtrace only */
     611             : #endif
     612             : 
     613          24 :         if (pim_ifp->pim_enable) {
     614             : 
     615          24 :                 if (!pim_addr_is_any(pim_ifp->primary_address)) {
     616             : 
     617             :                         /* Interface has a valid socket ? */
     618           8 :                         if (pim_ifp->pim_sock_fd < 0) {
     619           8 :                                 if (pim_sock_add(ifp)) {
     620           0 :                                         zlog_warn(
     621             :                                                 "Failure creating PIM socket for interface %s",
     622             :                                                 ifp->name);
     623             :                                 }
     624             :                         }
     625           8 :                         struct pim_nexthop_cache *pnc = NULL;
     626           8 :                         struct pim_rpf rpf;
     627           8 :                         struct zclient *zclient = NULL;
     628             : 
     629           8 :                         zclient = pim_zebra_zclient_get();
     630             :                         /* RP config might come prior to (local RP's interface)
     631             :                            IF UP event.
     632             :                            In this case, pnc would not have pim enabled
     633             :                            nexthops.
     634             :                            Once Interface is UP and pim info is available,
     635             :                            reregister
     636             :                            with RNH address to receive update and add the
     637             :                            interface as nexthop. */
     638           8 :                         memset(&rpf, 0, sizeof(struct pim_rpf));
     639           8 :                         rpf.rpf_addr = pim_addr_from_prefix(ifc->address);
     640           8 :                         pnc = pim_nexthop_cache_find(pim_ifp->pim, &rpf);
     641           8 :                         if (pnc)
     642           0 :                                 pim_sendmsg_zebra_rnh(pim_ifp->pim, zclient,
     643             :                                                       pnc,
     644             :                                                       ZEBRA_NEXTHOP_REGISTER);
     645             :                 }
     646             :         } /* pim */
     647             : 
     648             :         /*
     649             :           PIM or IGMP is enabled on interface, and there is at least one
     650             :           address assigned, then try to create a vif_index.
     651             :         */
     652          24 :         if (pim_ifp->mroute_vif_index < 0) {
     653           0 :                 vxlan_term = pim_vxlan_is_term_dev_cfg(pim_ifp->pim, ifp);
     654           0 :                 pim_if_add_vif(ifp, false, vxlan_term);
     655             :         }
     656          24 :         gm_ifp_update(ifp);
     657          24 :         pim_ifchannel_scan_forward_start(ifp);
     658             : }
     659             : 
     660             : static void pim_if_addr_del_igmp(struct connected *ifc)
     661             : {
     662             : #if PIM_IPV == 4
     663             :         struct pim_interface *pim_ifp = ifc->ifp->info;
     664             :         struct gm_sock *igmp;
     665             :         struct in_addr ifaddr;
     666             : 
     667             :         if (ifc->address->family != AF_INET) {
     668             :                 /* non-IPv4 address */
     669             :                 return;
     670             :         }
     671             : 
     672             :         if (!pim_ifp) {
     673             :                 /* IGMP not enabled on interface */
     674             :                 return;
     675             :         }
     676             : 
     677             :         ifaddr = ifc->address->u.prefix4;
     678             : 
     679             :         /* lookup IGMP socket */
     680             :         igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
     681             :         if (igmp) {
     682             :                 /* if addr found, del IGMP socket */
     683             :                 igmp_sock_delete(igmp);
     684             :         }
     685             : #endif
     686             : }
     687             : 
     688           0 : static void pim_if_addr_del_pim(struct connected *ifc)
     689             : {
     690           0 :         struct pim_interface *pim_ifp = ifc->ifp->info;
     691             : 
     692           0 :         if (ifc->address->family != PIM_AF) {
     693             :                 /* non-IPv4 address */
     694             :                 return;
     695             :         }
     696             : 
     697           0 :         if (!pim_ifp) {
     698             :                 /* PIM not enabled on interface */
     699             :                 return;
     700             :         }
     701             : 
     702           0 :         if (!pim_addr_is_any(pim_ifp->primary_address)) {
     703             :                 /* Interface keeps a valid primary address */
     704             :                 return;
     705             :         }
     706             : 
     707           0 :         if (pim_ifp->pim_sock_fd < 0) {
     708             :                 /* Interface does not hold a valid socket any longer */
     709             :                 return;
     710             :         }
     711             : 
     712             :         /*
     713             :           pim_sock_delete() closes the socket, stops read and timer threads,
     714             :           and kills all neighbors.
     715             :          */
     716           0 :         pim_sock_delete(ifc->ifp,
     717             :                         "last address has been removed from interface");
     718             : }
     719             : 
     720           0 : void pim_if_addr_del(struct connected *ifc, int force_prim_as_any)
     721             : {
     722           0 :         struct interface *ifp;
     723             : 
     724           0 :         assert(ifc);
     725           0 :         ifp = ifc->ifp;
     726           0 :         assert(ifp);
     727             : 
     728           0 :         if (PIM_DEBUG_ZEBRA)
     729           0 :                 zlog_debug("%s: %s ifindex=%d disconnected IP address %pFX %s",
     730             :                            __func__, ifp->name, ifp->ifindex, ifc->address,
     731             :                            CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)
     732             :                                    ? "secondary"
     733             :                                    : "primary");
     734             : 
     735             : #if PIM_IPV == 6
     736           0 :         struct pim_interface *pim_ifp = ifc->ifp->info;
     737             : 
     738           0 :         if (pim_ifp &&
     739           0 :             (!IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_lowest) ||
     740           0 :              !IPV6_ADDR_CMP(&ifc->address->u.prefix6, &pim_ifp->ll_highest))) {
     741           0 :                 struct listnode *cnode;
     742           0 :                 struct connected *cc;
     743             : 
     744           0 :                 memset(&pim_ifp->ll_lowest, 0xff, sizeof(pim_ifp->ll_lowest));
     745           0 :                 memset(&pim_ifp->ll_highest, 0, sizeof(pim_ifp->ll_highest));
     746             : 
     747           0 :                 for (ALL_LIST_ELEMENTS_RO(ifc->ifp->connected, cnode, cc)) {
     748           0 :                         if (!IN6_IS_ADDR_LINKLOCAL(&cc->address->u.prefix6) &&
     749           0 :                             !IN6_IS_ADDR_LOOPBACK(&cc->address->u.prefix6))
     750           0 :                                 continue;
     751             : 
     752           0 :                         if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
     753             :                                           &pim_ifp->ll_lowest) < 0)
     754           0 :                                 pim_ifp->ll_lowest = cc->address->u.prefix6;
     755           0 :                         if (IPV6_ADDR_CMP(&cc->address->u.prefix6,
     756             :                                           &pim_ifp->ll_highest) > 0)
     757           0 :                                 pim_ifp->ll_highest = cc->address->u.prefix6;
     758             :                 }
     759             : 
     760           0 :                 if (pim_ifp->ll_lowest.s6_addr[0] == 0xff)
     761           0 :                         memset(&pim_ifp->ll_lowest, 0,
     762             :                                sizeof(pim_ifp->ll_lowest));
     763             : 
     764           0 :                 if (PIM_DEBUG_ZEBRA)
     765           0 :                         zlog_debug(
     766             :                                 "%s: removed link-local %pI6, lowest now %pI6, highest %pI6",
     767             :                                 ifc->ifp->name, &ifc->address->u.prefix6,
     768             :                                 &pim_ifp->ll_lowest, &pim_ifp->ll_highest);
     769             : 
     770           0 :                 gm_ifp_update(ifp);
     771             :         }
     772             : #endif
     773             : 
     774           0 :         detect_address_change(ifp, force_prim_as_any, __func__);
     775             : 
     776           0 :         pim_if_addr_del_igmp(ifc);
     777           0 :         pim_if_addr_del_pim(ifc);
     778           0 : }
     779             : 
     780          48 : void pim_if_addr_add_all(struct interface *ifp)
     781             : {
     782          48 :         struct connected *ifc;
     783          48 :         struct listnode *node;
     784          48 :         struct listnode *nextnode;
     785          48 :         int v4_addrs = 0;
     786          48 :         int v6_addrs = 0;
     787          48 :         struct pim_interface *pim_ifp = ifp->info;
     788          48 :         bool vxlan_term;
     789             : 
     790             : 
     791             :         /* PIM/IGMP enabled ? */
     792          48 :         if (!pim_ifp)
     793             :                 return;
     794             : 
     795          82 :         for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
     796          26 :                 struct prefix *p = ifc->address;
     797             : 
     798          26 :                 if (p->family != AF_INET)
     799           6 :                         v6_addrs++;
     800             :                 else
     801          20 :                         v4_addrs++;
     802          26 :                 pim_if_addr_add(ifc);
     803             :         }
     804             : 
     805          28 :         if (!v4_addrs && v6_addrs && !if_is_loopback(ifp) &&
     806           0 :             pim_ifp->pim_enable && !pim_addr_is_any(pim_ifp->primary_address) &&
     807           0 :             pim_ifp->pim_sock_fd < 0 && pim_sock_add(ifp)) {
     808             :                 /* Interface has a valid primary address ? */
     809             :                 /* Interface has a valid socket ? */
     810           0 :                 zlog_warn("Failure creating PIM socket for interface %s",
     811             :                           ifp->name);
     812             :         }
     813             :         /*
     814             :          * PIM or IGMP/MLD is enabled on interface, and there is at least one
     815             :          * address assigned, then try to create a vif_index.
     816             :          */
     817          28 :         if (pim_ifp->mroute_vif_index < 0) {
     818           4 :                 vxlan_term = pim_vxlan_is_term_dev_cfg(pim_ifp->pim, ifp);
     819           4 :                 pim_if_add_vif(ifp, false, vxlan_term);
     820             :         }
     821          28 :         gm_ifp_update(ifp);
     822          28 :         pim_ifchannel_scan_forward_start(ifp);
     823             : 
     824          28 :         pim_rp_setup(pim_ifp->pim);
     825          28 :         pim_rp_check_on_if_add(pim_ifp);
     826             : }
     827             : 
     828           4 : void pim_if_addr_del_all(struct interface *ifp)
     829             : {
     830           4 :         struct connected *ifc;
     831           4 :         struct listnode *node;
     832           4 :         struct listnode *nextnode;
     833           4 :         struct pim_instance *pim;
     834             : 
     835           4 :         pim = ifp->vrf->info;
     836           4 :         if (!pim)
     837             :                 return;
     838             : 
     839             :         /* PIM/IGMP enabled ? */
     840           4 :         if (!ifp->info)
     841             :                 return;
     842             : 
     843          12 :         for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
     844           4 :                 struct prefix *p = ifc->address;
     845             : 
     846           4 :                 if (p->family != PIM_AF)
     847           4 :                         continue;
     848             : 
     849           0 :                 pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
     850             :         }
     851             : 
     852           4 :         pim_rp_setup(pim);
     853           4 :         pim_i_am_rp_re_evaluate(pim);
     854             : }
     855             : 
     856           0 : void pim_if_addr_del_all_igmp(struct interface *ifp)
     857             : {
     858           0 :         struct connected *ifc;
     859           0 :         struct listnode *node;
     860           0 :         struct listnode *nextnode;
     861             : 
     862             :         /* PIM/IGMP enabled ? */
     863           0 :         if (!ifp->info)
     864             :                 return;
     865             : 
     866           0 :         for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
     867           0 :                 struct prefix *p = ifc->address;
     868             : 
     869           0 :                 if (p->family != AF_INET)
     870             :                         continue;
     871             : 
     872             :                 pim_if_addr_del_igmp(ifc);
     873             :         }
     874             : }
     875             : 
     876          36 : pim_addr pim_find_primary_addr(struct interface *ifp)
     877             : {
     878          36 :         struct connected *ifc;
     879          36 :         struct listnode *node;
     880          36 :         struct pim_interface *pim_ifp = ifp->info;
     881             : 
     882          36 :         if (pim_ifp && !pim_addr_is_any(pim_ifp->update_source))
     883           0 :                 return pim_ifp->update_source;
     884             : 
     885             : #if PIM_IPV == 6
     886          36 :         if (pim_ifp && !pim_addr_is_any(pim_ifp->ll_highest))
     887           8 :                 return pim_ifp->ll_highest;
     888             : 
     889          28 :         pim_addr best_addr = PIMADDR_ANY;
     890             : 
     891          88 :         for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
     892          32 :                 pim_addr addr;
     893             : 
     894          32 :                 if (ifc->address->family != AF_INET6)
     895          24 :                         continue;
     896             : 
     897           8 :                 addr = pim_addr_from_prefix(ifc->address);
     898           8 :                 if (!IN6_IS_ADDR_LINKLOCAL(&addr))
     899           8 :                         continue;
     900           0 :                 if (pim_addr_cmp(addr, best_addr) > 0)
     901           0 :                         best_addr = addr;
     902             :         }
     903             : 
     904          28 :         return best_addr;
     905             : #else
     906             :         int v4_addrs = 0;
     907             :         int v6_addrs = 0;
     908             : 
     909             :         for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
     910             :                 switch (ifc->address->family) {
     911             :                 case AF_INET:
     912             :                         v4_addrs++;
     913             :                         break;
     914             :                 case AF_INET6:
     915             :                         v6_addrs++;
     916             :                         break;
     917             :                 default:
     918             :                         continue;
     919             :                 }
     920             : 
     921             :                 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
     922             :                         continue;
     923             : 
     924             :                 if (ifc->address->family != PIM_AF)
     925             :                         continue;
     926             : 
     927             :                 return pim_addr_from_prefix(ifc->address);
     928             :         }
     929             : 
     930             :         /*
     931             :          * If we have no v4_addrs and v6 is configured
     932             :          * We probably are using unnumbered
     933             :          * So let's grab the loopbacks v4 address
     934             :          * and use that as the primary address
     935             :          */
     936             :         if (!v4_addrs && v6_addrs) {
     937             :                 struct interface *lo_ifp;
     938             : 
     939             :                 // DBS - Come back and check here
     940             :                 if (ifp->vrf->vrf_id == VRF_DEFAULT)
     941             :                         lo_ifp = if_lookup_by_name("lo", ifp->vrf->vrf_id);
     942             :                 else
     943             :                         lo_ifp = if_lookup_by_name(ifp->vrf->name,
     944             :                                                    ifp->vrf->vrf_id);
     945             : 
     946             :                 if (lo_ifp && (lo_ifp != ifp))
     947             :                         return pim_find_primary_addr(lo_ifp);
     948             :         }
     949             :         return PIMADDR_ANY;
     950             : #endif
     951             : }
     952             : 
     953          16 : static int pim_iface_next_vif_index(struct interface *ifp)
     954             : {
     955          16 :         struct pim_interface *pim_ifp = ifp->info;
     956          16 :         struct pim_instance *pim = pim_ifp->pim;
     957          16 :         int i;
     958             : 
     959             :         /*
     960             :          * The pimreg vif is always going to be in index 0
     961             :          * of the table.
     962             :          */
     963          16 :         if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
     964             :                 return 0;
     965             : 
     966          18 :         for (i = 1; i < MAXVIFS; i++) {
     967          18 :                 if (pim->iface_vif_index[i] == 0)
     968          12 :                         return i;
     969             :         }
     970             :         return MAXVIFS;
     971             : }
     972             : 
     973             : /*
     974             :   pim_if_add_vif() uses ifindex as vif_index
     975             : 
     976             :   see also pim_if_find_vifindex_by_ifindex()
     977             :  */
     978          16 : int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term)
     979             : {
     980          16 :         struct pim_interface *pim_ifp = ifp->info;
     981          16 :         pim_addr ifaddr;
     982          16 :         unsigned char flags = 0;
     983             : 
     984          16 :         assert(pim_ifp);
     985             : 
     986          16 :         if (pim_ifp->mroute_vif_index > 0) {
     987           0 :                 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
     988             :                           __func__, pim_ifp->mroute_vif_index, ifp->name,
     989             :                           ifp->ifindex);
     990           0 :                 return -1;
     991             :         }
     992             : 
     993          16 :         if (ifp->ifindex < 0) {
     994           0 :                 zlog_warn("%s: ifindex=%d < 1 on interface %s", __func__,
     995             :                           ifp->ifindex, ifp->name);
     996           0 :                 return -2;
     997             :         }
     998             : 
     999          16 :         ifaddr = pim_ifp->primary_address;
    1000             : #if PIM_IPV != 6
    1001             :         /* IPv6 API is always by interface index */
    1002             :         if (!ispimreg && !is_vxlan_term && pim_addr_is_any(ifaddr)) {
    1003             :                 zlog_warn(
    1004             :                         "%s: could not get address for interface %s ifindex=%d",
    1005             :                         __func__, ifp->name, ifp->ifindex);
    1006             :                 return -4;
    1007             :         }
    1008             : #endif
    1009             : 
    1010          16 :         pim_ifp->mroute_vif_index = pim_iface_next_vif_index(ifp);
    1011             : 
    1012          16 :         if (pim_ifp->mroute_vif_index >= MAXVIFS) {
    1013           0 :                 zlog_warn(
    1014             :                         "%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
    1015             :                         __func__, MAXVIFS, ifp->name);
    1016           0 :                 return -3;
    1017             :         }
    1018             : 
    1019          16 :         if (ifp->ifindex == PIM_OIF_PIM_REGISTER_VIF)
    1020           4 :                 flags = VIFF_REGISTER;
    1021             : #ifdef VIFF_USE_IFINDEX
    1022             :         else
    1023             :                 flags = VIFF_USE_IFINDEX;
    1024             : #endif
    1025             : 
    1026          16 :         if (pim_mroute_add_vif(ifp, ifaddr, flags)) {
    1027             :                 /* pim_mroute_add_vif reported error */
    1028             :                 return -5;
    1029             :         }
    1030             : 
    1031          16 :         pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 1;
    1032             : 
    1033          16 :         if (!ispimreg)
    1034          12 :                 gm_ifp_update(ifp);
    1035             : 
    1036             :         /* if the device qualifies as pim_vxlan iif/oif update vxlan entries */
    1037          16 :         pim_vxlan_add_vif(ifp);
    1038          16 :         return 0;
    1039             : }
    1040             : 
    1041          16 : int pim_if_del_vif(struct interface *ifp)
    1042             : {
    1043          16 :         struct pim_interface *pim_ifp = ifp->info;
    1044             : 
    1045          16 :         if (pim_ifp->mroute_vif_index < 1) {
    1046           4 :                 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
    1047             :                           __func__, pim_ifp->mroute_vif_index, ifp->name,
    1048             :                           ifp->ifindex);
    1049           4 :                 return -1;
    1050             :         }
    1051             : 
    1052             :         /* if the device was a pim_vxlan iif/oif update vxlan mroute entries */
    1053          12 :         pim_vxlan_del_vif(ifp);
    1054             : 
    1055          12 :         gm_ifp_teardown(ifp);
    1056             : 
    1057          12 :         pim_mroute_del_vif(ifp);
    1058             : 
    1059             :         /*
    1060             :           Update vif_index
    1061             :          */
    1062          12 :         pim_ifp->pim->iface_vif_index[pim_ifp->mroute_vif_index] = 0;
    1063             : 
    1064          12 :         pim_ifp->mroute_vif_index = -1;
    1065          12 :         return 0;
    1066             : }
    1067             : 
    1068             : // DBS - VRF Revist
    1069          27 : struct interface *pim_if_find_by_vif_index(struct pim_instance *pim,
    1070             :                                            ifindex_t vif_index)
    1071             : {
    1072          27 :         struct interface *ifp;
    1073             : 
    1074         113 :         FOR_ALL_INTERFACES (pim->vrf, ifp) {
    1075          86 :                 if (ifp->info) {
    1076          59 :                         struct pim_interface *pim_ifp;
    1077          59 :                         pim_ifp = ifp->info;
    1078             : 
    1079          59 :                         if (vif_index == pim_ifp->mroute_vif_index)
    1080          27 :                                 return ifp;
    1081             :                 }
    1082             :         }
    1083             : 
    1084             :         return 0;
    1085             : }
    1086             : 
    1087             : /*
    1088             :   pim_if_add_vif() uses ifindex as vif_index
    1089             :  */
    1090           1 : int pim_if_find_vifindex_by_ifindex(struct pim_instance *pim, ifindex_t ifindex)
    1091             : {
    1092           1 :         struct pim_interface *pim_ifp;
    1093           1 :         struct interface *ifp;
    1094             : 
    1095           1 :         ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
    1096           1 :         if (!ifp || !ifp->info)
    1097             :                 return -1;
    1098           1 :         pim_ifp = ifp->info;
    1099             : 
    1100           1 :         return pim_ifp->mroute_vif_index;
    1101             : }
    1102             : 
    1103          23 : int pim_if_lan_delay_enabled(struct interface *ifp)
    1104             : {
    1105          23 :         struct pim_interface *pim_ifp;
    1106             : 
    1107          23 :         pim_ifp = ifp->info;
    1108          23 :         assert(pim_ifp);
    1109          23 :         assert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
    1110             : 
    1111          23 :         return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
    1112             : }
    1113             : 
    1114           0 : uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
    1115             : {
    1116           0 :         if (pim_if_lan_delay_enabled(ifp)) {
    1117           0 :                 struct pim_interface *pim_ifp;
    1118           0 :                 pim_ifp = ifp->info;
    1119           0 :                 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
    1120             :         } else {
    1121             :                 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
    1122             :         }
    1123             : }
    1124             : 
    1125           0 : uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
    1126             : {
    1127           0 :         if (pim_if_lan_delay_enabled(ifp)) {
    1128           0 :                 struct pim_interface *pim_ifp;
    1129           0 :                 pim_ifp = ifp->info;
    1130           0 :                 return pim_ifp->pim_neighbors_highest_override_interval_msec;
    1131             :         } else {
    1132             :                 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
    1133             :         }
    1134             : }
    1135             : 
    1136           0 : int pim_if_t_override_msec(struct interface *ifp)
    1137             : {
    1138           0 :         int effective_override_interval_msec;
    1139           0 :         int t_override_msec;
    1140             : 
    1141           0 :         effective_override_interval_msec =
    1142           0 :                 pim_if_effective_override_interval_msec(ifp);
    1143             : 
    1144           0 :         t_override_msec =
    1145           0 :                 frr_weak_random() % (effective_override_interval_msec + 1);
    1146             : 
    1147           0 :         return t_override_msec;
    1148             : }
    1149             : 
    1150           0 : uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
    1151             : {
    1152           0 :         return pim_if_effective_propagation_delay_msec(ifp)
    1153           0 :                + pim_if_effective_override_interval_msec(ifp);
    1154             : }
    1155             : 
    1156             : /*
    1157             :   RFC 4601: 4.1.6.  State Summarization Macros
    1158             : 
    1159             :   The function NBR( I, A ) uses information gathered through PIM Hello
    1160             :   messages to map the IP address A of a directly connected PIM
    1161             :   neighbor router on interface I to the primary IP address of the same
    1162             :   router (Section 4.3.4).  The primary IP address of a neighbor is the
    1163             :   address that it uses as the source of its PIM Hello messages.
    1164             : */
    1165           8 : struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp, pim_addr addr)
    1166             : {
    1167           8 :         struct listnode *neighnode;
    1168           8 :         struct pim_neighbor *neigh;
    1169           8 :         struct pim_interface *pim_ifp;
    1170           8 :         struct prefix p;
    1171             : 
    1172           8 :         assert(ifp);
    1173             : 
    1174           8 :         pim_ifp = ifp->info;
    1175           8 :         if (!pim_ifp) {
    1176           0 :                 zlog_warn("%s: multicast not enabled on interface %s", __func__,
    1177             :                           ifp->name);
    1178           0 :                 return 0;
    1179             :         }
    1180             : 
    1181           8 :         pim_addr_to_prefix(&p, addr);
    1182             : 
    1183          16 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode,
    1184             :                                   neigh)) {
    1185             : 
    1186             :                 /* primary address ? */
    1187           6 :                 if (!pim_addr_cmp(neigh->source_addr, addr))
    1188           6 :                         return neigh;
    1189             : 
    1190             :                 /* secondary address ? */
    1191           0 :                 if (pim_neighbor_find_secondary(neigh, &p))
    1192           0 :                         return neigh;
    1193             :         }
    1194             : 
    1195           2 :         if (PIM_DEBUG_PIM_TRACE)
    1196           0 :                 zlog_debug(
    1197             :                         "%s: neighbor not found for address %pPA on interface %s",
    1198             :                         __func__, &addr, ifp->name);
    1199             : 
    1200             :         return NULL;
    1201             : }
    1202             : 
    1203           0 : long pim_if_t_suppressed_msec(struct interface *ifp)
    1204             : {
    1205           0 :         struct pim_interface *pim_ifp;
    1206           0 :         long t_suppressed_msec;
    1207           0 :         uint32_t ramount = 0;
    1208             : 
    1209           0 :         pim_ifp = ifp->info;
    1210           0 :         assert(pim_ifp);
    1211             : 
    1212             :         /* join suppression disabled ? */
    1213           0 :         if (pim_ifp->pim_can_disable_join_suppression)
    1214             :                 return 0;
    1215             : 
    1216             :         /* t_suppressed = t_periodic * rand(1.1, 1.4) */
    1217           0 :         ramount = 1100 + (frr_weak_random() % (1400 - 1100 + 1));
    1218           0 :         t_suppressed_msec = router->t_periodic * ramount;
    1219             : 
    1220           0 :         return t_suppressed_msec;
    1221             : }
    1222             : 
    1223             : #if PIM_IPV == 4
    1224             : static void igmp_join_free(struct gm_join *ij)
    1225             : {
    1226             :         XFREE(MTYPE_PIM_IGMP_JOIN, ij);
    1227             : }
    1228             : 
    1229             : static struct gm_join *igmp_join_find(struct list *join_list,
    1230             :                                       struct in_addr group_addr,
    1231             :                                       struct in_addr source_addr)
    1232             : {
    1233             :         struct listnode *node;
    1234             :         struct gm_join *ij;
    1235             : 
    1236             :         assert(join_list);
    1237             : 
    1238             :         for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
    1239             :                 if ((group_addr.s_addr == ij->group_addr.s_addr)
    1240             :                     && (source_addr.s_addr == ij->source_addr.s_addr))
    1241             :                         return ij;
    1242             :         }
    1243             : 
    1244             :         return 0;
    1245             : }
    1246             : 
    1247             : static int igmp_join_sock(const char *ifname, ifindex_t ifindex,
    1248             :                           struct in_addr group_addr, struct in_addr source_addr,
    1249             :                           struct pim_interface *pim_ifp)
    1250             : {
    1251             :         int join_fd;
    1252             : 
    1253             :         pim_ifp->igmp_ifstat_joins_sent++;
    1254             : 
    1255             :         join_fd = pim_socket_raw(IPPROTO_IGMP);
    1256             :         if (join_fd < 0) {
    1257             :                 pim_ifp->igmp_ifstat_joins_failed++;
    1258             :                 return -1;
    1259             :         }
    1260             : 
    1261             :         if (pim_igmp_join_source(join_fd, ifindex, group_addr, source_addr)) {
    1262             :                 char group_str[INET_ADDRSTRLEN];
    1263             :                 char source_str[INET_ADDRSTRLEN];
    1264             :                 pim_inet4_dump("<grp?>", group_addr, group_str,
    1265             :                                sizeof(group_str));
    1266             :                 pim_inet4_dump("<src?>", source_addr, source_str,
    1267             :                                sizeof(source_str));
    1268             :                 zlog_warn(
    1269             :                         "%s: setsockopt(fd=%d) failure for IGMP group %s source %s ifindex %d on interface %s: errno=%d: %s",
    1270             :                         __func__, join_fd, group_str, source_str, ifindex,
    1271             :                         ifname, errno, safe_strerror(errno));
    1272             : 
    1273             :                 pim_ifp->igmp_ifstat_joins_failed++;
    1274             : 
    1275             :                 close(join_fd);
    1276             :                 return -2;
    1277             :         }
    1278             : 
    1279             :         return join_fd;
    1280             : }
    1281             : 
    1282             : #if PIM_IPV == 4
    1283             : static struct gm_join *igmp_join_new(struct interface *ifp,
    1284             :                                      struct in_addr group_addr,
    1285             :                                      struct in_addr source_addr)
    1286             : {
    1287             :         struct pim_interface *pim_ifp;
    1288             :         struct gm_join *ij;
    1289             :         int join_fd;
    1290             : 
    1291             :         pim_ifp = ifp->info;
    1292             :         assert(pim_ifp);
    1293             : 
    1294             :         join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr,
    1295             :                                  source_addr, pim_ifp);
    1296             :         if (join_fd < 0) {
    1297             :                 char group_str[INET_ADDRSTRLEN];
    1298             :                 char source_str[INET_ADDRSTRLEN];
    1299             : 
    1300             :                 pim_inet4_dump("<grp?>", group_addr, group_str,
    1301             :                                sizeof(group_str));
    1302             :                 pim_inet4_dump("<src?>", source_addr, source_str,
    1303             :                                sizeof(source_str));
    1304             :                 zlog_warn(
    1305             :                         "%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
    1306             :                         __func__, group_str, source_str, ifp->name);
    1307             :                 return 0;
    1308             :         }
    1309             : 
    1310             :         ij = XCALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
    1311             : 
    1312             :         ij->sock_fd = join_fd;
    1313             :         ij->group_addr = group_addr;
    1314             :         ij->source_addr = source_addr;
    1315             :         ij->sock_creation = pim_time_monotonic_sec();
    1316             : 
    1317             :         listnode_add(pim_ifp->gm_join_list, ij);
    1318             : 
    1319             :         return ij;
    1320             : }
    1321             : #endif /* PIM_IPV == 4 */
    1322             : 
    1323             : #if PIM_IPV == 4
    1324             : ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
    1325             :                             struct in_addr source_addr)
    1326             : {
    1327             :         struct pim_interface *pim_ifp;
    1328             :         struct gm_join *ij;
    1329             : 
    1330             :         pim_ifp = ifp->info;
    1331             :         if (!pim_ifp) {
    1332             :                 return ferr_cfg_invalid("multicast not enabled on interface %s",
    1333             :                                         ifp->name);
    1334             :         }
    1335             : 
    1336             :         if (!pim_ifp->gm_join_list) {
    1337             :                 pim_ifp->gm_join_list = list_new();
    1338             :                 pim_ifp->gm_join_list->del = (void (*)(void *))igmp_join_free;
    1339             :         }
    1340             : 
    1341             :         ij = igmp_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
    1342             : 
    1343             :         /* This interface has already been configured to join this IGMP group
    1344             :          */
    1345             :         if (ij) {
    1346             :                 return ferr_ok();
    1347             :         }
    1348             : 
    1349             :         (void)igmp_join_new(ifp, group_addr, source_addr);
    1350             : 
    1351             :         if (PIM_DEBUG_GM_EVENTS) {
    1352             :                 char group_str[INET_ADDRSTRLEN];
    1353             :                 char source_str[INET_ADDRSTRLEN];
    1354             :                 pim_inet4_dump("<grp?>", group_addr, group_str,
    1355             :                                sizeof(group_str));
    1356             :                 pim_inet4_dump("<src?>", source_addr, source_str,
    1357             :                                sizeof(source_str));
    1358             :                 zlog_debug(
    1359             :                         "%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
    1360             :                         __func__, source_str, group_str, ifp->name);
    1361             :         }
    1362             : 
    1363             :         return ferr_ok();
    1364             : }
    1365             : #endif /* PIM_IPV == 4 */
    1366             : 
    1367             : int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
    1368             :                          struct in_addr source_addr)
    1369             : {
    1370             :         struct pim_interface *pim_ifp;
    1371             :         struct gm_join *ij;
    1372             : 
    1373             :         pim_ifp = ifp->info;
    1374             :         if (!pim_ifp) {
    1375             :                 zlog_warn("%s: multicast not enabled on interface %s", __func__,
    1376             :                           ifp->name);
    1377             :                 return -1;
    1378             :         }
    1379             : 
    1380             :         if (!pim_ifp->gm_join_list) {
    1381             :                 zlog_warn("%s: no IGMP join on interface %s", __func__,
    1382             :                           ifp->name);
    1383             :                 return -2;
    1384             :         }
    1385             : 
    1386             :         ij = igmp_join_find(pim_ifp->gm_join_list, group_addr, source_addr);
    1387             :         if (!ij) {
    1388             :                 char group_str[INET_ADDRSTRLEN];
    1389             :                 char source_str[INET_ADDRSTRLEN];
    1390             :                 pim_inet4_dump("<grp?>", group_addr, group_str,
    1391             :                                sizeof(group_str));
    1392             :                 pim_inet4_dump("<src?>", source_addr, source_str,
    1393             :                                sizeof(source_str));
    1394             :                 zlog_warn(
    1395             :                         "%s: could not find IGMP group %s source %s on interface %s",
    1396             :                         __func__, group_str, source_str, ifp->name);
    1397             :                 return -3;
    1398             :         }
    1399             : 
    1400             :         if (close(ij->sock_fd)) {
    1401             :                 char group_str[INET_ADDRSTRLEN];
    1402             :                 char source_str[INET_ADDRSTRLEN];
    1403             :                 pim_inet4_dump("<grp?>", group_addr, group_str,
    1404             :                                sizeof(group_str));
    1405             :                 pim_inet4_dump("<src?>", source_addr, source_str,
    1406             :                                sizeof(source_str));
    1407             :                 zlog_warn(
    1408             :                         "%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
    1409             :                         __func__, ij->sock_fd, group_str, source_str, ifp->name,
    1410             :                         errno, safe_strerror(errno));
    1411             :                 /* warning only */
    1412             :         }
    1413             :         listnode_delete(pim_ifp->gm_join_list, ij);
    1414             :         igmp_join_free(ij);
    1415             :         if (listcount(pim_ifp->gm_join_list) < 1) {
    1416             :                 list_delete(&pim_ifp->gm_join_list);
    1417             :                 pim_ifp->gm_join_list = 0;
    1418             :         }
    1419             : 
    1420             :         return 0;
    1421             : }
    1422             : 
    1423             : __attribute__((unused))
    1424             : static void pim_if_igmp_join_del_all(struct interface *ifp)
    1425             : {
    1426             :         struct pim_interface *pim_ifp;
    1427             :         struct listnode *node;
    1428             :         struct listnode *nextnode;
    1429             :         struct gm_join *ij;
    1430             : 
    1431             :         pim_ifp = ifp->info;
    1432             :         if (!pim_ifp) {
    1433             :                 zlog_warn("%s: multicast not enabled on interface %s", __func__,
    1434             :                           ifp->name);
    1435             :                 return;
    1436             :         }
    1437             : 
    1438             :         if (!pim_ifp->gm_join_list)
    1439             :                 return;
    1440             : 
    1441             :         for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij))
    1442             :                 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
    1443             : }
    1444             : #else /* PIM_IPV != 4 */
    1445           0 : ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr,
    1446             :                             struct in_addr source_addr)
    1447             : {
    1448           0 :         return ferr_ok();
    1449             : }
    1450             : 
    1451           0 : int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr,
    1452             :                          struct in_addr source_addr)
    1453             : {
    1454           0 :         return 0;
    1455             : }
    1456             : #endif /* PIM_IPV != 4 */
    1457             : 
    1458             : /*
    1459             :   RFC 4601
    1460             : 
    1461             :   Transitions from "I am Assert Loser" State
    1462             : 
    1463             :   Current Winner's GenID Changes or NLT Expires
    1464             : 
    1465             :   The Neighbor Liveness Timer associated with the current winner
    1466             :   expires or we receive a Hello message from the current winner
    1467             :   reporting a different GenID from the one it previously reported.
    1468             :   This indicates that the current winner's interface or router has
    1469             :   gone down (and may have come back up), and so we must assume it no
    1470             :   longer knows it was the winner.
    1471             :  */
    1472           6 : void pim_if_assert_on_neighbor_down(struct interface *ifp, pim_addr neigh_addr)
    1473             : {
    1474           6 :         struct pim_interface *pim_ifp;
    1475           6 :         struct pim_ifchannel *ch;
    1476             : 
    1477           6 :         pim_ifp = ifp->info;
    1478           6 :         assert(pim_ifp);
    1479             : 
    1480          12 :         RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
    1481             :                 /* Is (S,G,I) assert loser ? */
    1482           0 :                 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
    1483           0 :                         continue;
    1484             :                 /* Dead neighbor was winner ? */
    1485           0 :                 if (pim_addr_cmp(ch->ifassert_winner, neigh_addr))
    1486           0 :                         continue;
    1487             : 
    1488           0 :                 assert_action_a5(ch);
    1489             :         }
    1490           6 : }
    1491             : 
    1492          21 : void pim_if_update_join_desired(struct pim_interface *pim_ifp)
    1493             : {
    1494          21 :         struct pim_ifchannel *ch;
    1495             : 
    1496             :         /* clear off flag from interface's upstreams */
    1497          42 :         RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
    1498           0 :                 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(
    1499             :                         ch->upstream->flags);
    1500             :         }
    1501             : 
    1502             :         /* scan per-interface (S,G,I) state on this I interface */
    1503          42 :         RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
    1504           0 :                 struct pim_upstream *up = ch->upstream;
    1505             : 
    1506           0 :                 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
    1507           0 :                         continue;
    1508             : 
    1509             :                 /* update join_desired for the global (S,G) state */
    1510           0 :                 pim_upstream_update_join_desired(pim_ifp->pim, up);
    1511           0 :                 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
    1512             :         }
    1513          21 : }
    1514             : 
    1515          21 : void pim_if_update_assert_tracking_desired(struct interface *ifp)
    1516             : {
    1517          21 :         struct pim_interface *pim_ifp;
    1518          21 :         struct pim_ifchannel *ch;
    1519             : 
    1520          21 :         pim_ifp = ifp->info;
    1521          21 :         if (!pim_ifp)
    1522             :                 return;
    1523             : 
    1524          42 :         RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
    1525           0 :                 pim_ifchannel_update_assert_tracking_desired(ch);
    1526             :         }
    1527             : }
    1528             : 
    1529             : /*
    1530             :  * PIM wants to have an interface pointer for everything it does.
    1531             :  * The pimreg is a special interface that we have that is not
    1532             :  * quite an interface but a VIF is created for it.
    1533             :  */
    1534          32 : void pim_if_create_pimreg(struct pim_instance *pim)
    1535             : {
    1536          32 :         char pimreg_name[INTERFACE_NAMSIZ];
    1537             : 
    1538          32 :         if (!pim->regiface) {
    1539           4 :                 if (pim->vrf->vrf_id == VRF_DEFAULT)
    1540           4 :                         strlcpy(pimreg_name, PIMREG, sizeof(pimreg_name));
    1541             :                 else
    1542           0 :                         snprintf(pimreg_name, sizeof(pimreg_name), PIMREG "%u",
    1543             :                                  pim->vrf->data.l.table_id);
    1544             : 
    1545           8 :                 pim->regiface = if_get_by_name(pimreg_name, pim->vrf->vrf_id,
    1546           4 :                                                pim->vrf->name);
    1547           4 :                 pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF;
    1548             : 
    1549           4 :                 pim_if_new(pim->regiface, false, false, true,
    1550             :                         false /*vxlan_term*/);
    1551             :                 /*
    1552             :                  * On vrf moves we delete the interface if there
    1553             :                  * is nothing going on with it.  We cannot have
    1554             :                  * the pimregiface deleted.
    1555             :                  */
    1556           4 :                 pim->regiface->configured = true;
    1557             : 
    1558             :         }
    1559          32 : }
    1560             : 
    1561          39 : struct prefix *pim_if_connected_to_source(struct interface *ifp, pim_addr src)
    1562             : {
    1563          39 :         struct listnode *cnode;
    1564          39 :         struct connected *c;
    1565          39 :         struct prefix p;
    1566             : 
    1567          39 :         if (!ifp)
    1568             :                 return NULL;
    1569             : 
    1570          35 :         pim_addr_to_prefix(&p, src);
    1571             : 
    1572         131 :         for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
    1573          70 :                 if (c->address->family != PIM_AF)
    1574          35 :                         continue;
    1575          35 :                 if (prefix_match(c->address, &p))
    1576           9 :                         return c->address;
    1577          26 :                 if (CONNECTED_PEER(c) && prefix_match(c->destination, &p))
    1578             :                         /* this is not a typo, on PtP we need to return the
    1579             :                          * *local* address that lines up with src.
    1580             :                          */
    1581           0 :                         return c->address;
    1582             :         }
    1583             : 
    1584             :         return NULL;
    1585             : }
    1586             : 
    1587           0 : bool pim_if_is_vrf_device(struct interface *ifp)
    1588             : {
    1589           0 :         if (if_is_vrf(ifp))
    1590           0 :                 return true;
    1591             : 
    1592             :         return false;
    1593             : }
    1594             : 
    1595           0 : int pim_if_ifchannel_count(struct pim_interface *pim_ifp)
    1596             : {
    1597           0 :         struct pim_ifchannel *ch;
    1598           0 :         int count = 0;
    1599             : 
    1600           0 :         RB_FOREACH (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb) {
    1601           0 :                 count++;
    1602             :         }
    1603             : 
    1604           0 :         return count;
    1605             : }
    1606             : 
    1607          28 : static int pim_ifp_create(struct interface *ifp)
    1608             : {
    1609          28 :         struct pim_instance *pim;
    1610             : 
    1611          28 :         pim = ifp->vrf->info;
    1612          28 :         if (PIM_DEBUG_ZEBRA) {
    1613           0 :                 zlog_debug(
    1614             :                         "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
    1615             :                         __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
    1616             :                         ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
    1617             :                         ifp->mtu, if_is_operative(ifp));
    1618             :         }
    1619             : 
    1620          28 :         if (if_is_operative(ifp)) {
    1621          16 :                 struct pim_interface *pim_ifp;
    1622             : 
    1623          16 :                 pim_ifp = ifp->info;
    1624             :                 /*
    1625             :                  * If we have a pim_ifp already and this is an if_add
    1626             :                  * that means that we probably have a vrf move event
    1627             :                  * If that is the case, set the proper vrfness.
    1628             :                  */
    1629          16 :                 if (pim_ifp)
    1630           0 :                         pim_ifp->pim = pim;
    1631          16 :                 pim_if_addr_add_all(ifp);
    1632             : 
    1633             :                 /*
    1634             :                  * Due to ordering issues based upon when
    1635             :                  * a command is entered we should ensure that
    1636             :                  * the pim reg is created for this vrf if we
    1637             :                  * have configuration for it already.
    1638             :                  *
    1639             :                  * this is a no-op if it's already been done.
    1640             :                  */
    1641          16 :                 pim_if_create_pimreg(pim);
    1642             :         }
    1643             : 
    1644             : #if PIM_IPV == 4
    1645             :         /*
    1646             :          * If we are a vrf device that is up, open up the pim_socket for
    1647             :          * listening
    1648             :          * to incoming pim messages irrelevant if the user has configured us
    1649             :          * for pim or not.
    1650             :          */
    1651             :         if (pim_if_is_vrf_device(ifp)) {
    1652             :                 struct pim_interface *pim_ifp;
    1653             : 
    1654             :                 if (!ifp->info) {
    1655             :                         pim_ifp = pim_if_new(ifp, false, false, false,
    1656             :                                              false /*vxlan_term*/);
    1657             :                         ifp->info = pim_ifp;
    1658             :                 }
    1659             : 
    1660             :                 pim_sock_add(ifp);
    1661             :         }
    1662             : 
    1663             :         if (!strncmp(ifp->name, PIM_VXLAN_TERM_DEV_NAME,
    1664             :                      sizeof(PIM_VXLAN_TERM_DEV_NAME))) {
    1665             :                 if (pim->mcast_if_count < MAXVIFS)
    1666             :                         pim_vxlan_add_term_dev(pim, ifp);
    1667             :                 else
    1668             :                         zlog_warn(
    1669             :                                 "%s: Cannot enable pim on %s. MAXVIFS(%d) reached. Deleting and readding the vxlan termimation device after unconfiguring pim from other interfaces may succeed.",
    1670             :                                 __func__, ifp->name, MAXVIFS);
    1671             :         }
    1672             : #endif
    1673             : 
    1674          28 :         return 0;
    1675             : }
    1676             : 
    1677          12 : static int pim_ifp_up(struct interface *ifp)
    1678             : {
    1679          12 :         uint32_t table_id;
    1680          12 :         struct pim_interface *pim_ifp;
    1681          12 :         struct pim_instance *pim;
    1682             : 
    1683          12 :         if (PIM_DEBUG_ZEBRA) {
    1684           0 :                 zlog_debug(
    1685             :                         "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
    1686             :                         __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
    1687             :                         ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
    1688             :                         ifp->mtu, if_is_operative(ifp));
    1689             :         }
    1690             : 
    1691          12 :         pim = ifp->vrf->info;
    1692             : 
    1693          12 :         pim_ifp = ifp->info;
    1694             :         /*
    1695             :          * If we have a pim_ifp already and this is an if_add
    1696             :          * that means that we probably have a vrf move event
    1697             :          * If that is the case, set the proper vrfness.
    1698             :          */
    1699          12 :         if (pim_ifp)
    1700          12 :                 pim_ifp->pim = pim;
    1701             : 
    1702             :         /*
    1703             :           pim_if_addr_add_all() suffices for bringing up both IGMP and
    1704             :           PIM
    1705             :         */
    1706          12 :         pim_if_addr_add_all(ifp);
    1707             : 
    1708             :         /*
    1709             :          * If we have a pimreg device callback and it's for a specific
    1710             :          * table set the master appropriately
    1711             :          */
    1712          12 :         if (sscanf(ifp->name, "" PIMREG "%" SCNu32, &table_id) == 1) {
    1713           0 :                 struct vrf *vrf;
    1714           0 :                 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
    1715           0 :                         if ((table_id == vrf->data.l.table_id)
    1716           0 :                             && (ifp->vrf->vrf_id != vrf->vrf_id)) {
    1717           0 :                                 struct interface *master = if_lookup_by_name(
    1718           0 :                                         vrf->name, vrf->vrf_id);
    1719             : 
    1720           0 :                                 if (!master) {
    1721           0 :                                         zlog_debug(
    1722             :                                                 "%s: Unable to find Master interface for %s",
    1723             :                                                 __func__, vrf->name);
    1724           0 :                                         return 0;
    1725             :                                 }
    1726           0 :                                 pim_zebra_interface_set_master(master, ifp);
    1727             :                         }
    1728             :                 }
    1729             :         }
    1730             :         return 0;
    1731             : }
    1732             : 
    1733           4 : static int pim_ifp_down(struct interface *ifp)
    1734             : {
    1735           4 :         if (PIM_DEBUG_ZEBRA) {
    1736           0 :                 zlog_debug(
    1737             :                         "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
    1738             :                         __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
    1739             :                         ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
    1740             :                         ifp->mtu, if_is_operative(ifp));
    1741             :         }
    1742             : 
    1743           4 :         if (!if_is_operative(ifp)) {
    1744           4 :                 pim_ifchannel_delete_all(ifp);
    1745             :                 /*
    1746             :                   pim_if_addr_del_all() suffices for shutting down IGMP,
    1747             :                   but not for shutting down PIM
    1748             :                 */
    1749           4 :                 pim_if_addr_del_all(ifp);
    1750             : 
    1751             :                 /*
    1752             :                   pim_sock_delete() closes the socket, stops read and timer
    1753             :                   threads,
    1754             :                   and kills all neighbors.
    1755             :                 */
    1756           4 :                 if (ifp->info) {
    1757           4 :                         pim_sock_delete(ifp, "link down");
    1758             :                 }
    1759             :         }
    1760             : 
    1761           4 :         if (ifp->info) {
    1762           4 :                 pim_if_del_vif(ifp);
    1763           4 :                 pim_ifstat_reset(ifp);
    1764             :         }
    1765             : 
    1766           4 :         return 0;
    1767             : }
    1768             : 
    1769           0 : static int pim_ifp_destroy(struct interface *ifp)
    1770             : {
    1771           0 :         if (PIM_DEBUG_ZEBRA) {
    1772           0 :                 zlog_debug(
    1773             :                         "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d",
    1774             :                         __func__, ifp->name, ifp->ifindex, ifp->vrf->name,
    1775             :                         ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric,
    1776             :                         ifp->mtu, if_is_operative(ifp));
    1777             :         }
    1778             : 
    1779           0 :         if (!if_is_operative(ifp))
    1780           0 :                 pim_if_addr_del_all(ifp);
    1781             : 
    1782             : #if PIM_IPV == 4
    1783             :         struct pim_instance *pim;
    1784             : 
    1785             :         pim = ifp->vrf->info;
    1786             :         if (pim && pim->vxlan.term_if == ifp)
    1787             :                 pim_vxlan_del_term_dev(pim);
    1788             : #endif
    1789             : 
    1790           0 :         return 0;
    1791             : }
    1792             : 
    1793          16 : static int pim_if_new_hook(struct interface *ifp)
    1794             : {
    1795          16 :         return 0;
    1796             : }
    1797             : 
    1798          16 : static int pim_if_delete_hook(struct interface *ifp)
    1799             : {
    1800          16 :         if (ifp->info)
    1801           0 :                 pim_if_delete(ifp);
    1802             : 
    1803          16 :         return 0;
    1804             : }
    1805             : 
    1806           4 : void pim_iface_init(void)
    1807             : {
    1808           4 :         hook_register_prio(if_add, 0, pim_if_new_hook);
    1809           4 :         hook_register_prio(if_del, 0, pim_if_delete_hook);
    1810             : 
    1811           4 :         if_zapi_callbacks(pim_ifp_create, pim_ifp_up, pim_ifp_down,
    1812             :                           pim_ifp_destroy);
    1813           4 : }

Generated by: LCOV version v1.16-topotato