back to topotato report
topotato coverage report
Current view: top level - pimd - pim_join.c (source / functions) Hit Total Coverage
Test: test_pim_crp.py::PIMCandidateBSRTest Lines: 0 232 0.0 %
Date: 2023-02-16 02:09:37 Functions: 0 5 0.0 %

          Line data    Source code
       1             : 
       2             : 
       3             : /*
       4             :  * PIM for Quagga
       5             :  * Copyright (C) 2008  Everton da Silva Marques
       6             :  *
       7             :  * This program is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published by
       9             :  * the Free Software Foundation; either version 2 of the License, or
      10             :  * (at your option) any later version.
      11             :  *
      12             :  * This program is distributed in the hope that it will be useful, but
      13             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with this program; see the file COPYING; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : 
      24             : #include "log.h"
      25             : #include "prefix.h"
      26             : #include "if.h"
      27             : #include "vty.h"
      28             : #include "plist.h"
      29             : 
      30             : #include "pimd.h"
      31             : #include "pim_instance.h"
      32             : #include "pim_str.h"
      33             : #include "pim_tlv.h"
      34             : #include "pim_msg.h"
      35             : #include "pim_pim.h"
      36             : #include "pim_join.h"
      37             : #include "pim_oil.h"
      38             : #include "pim_iface.h"
      39             : #include "pim_hello.h"
      40             : #include "pim_ifchannel.h"
      41             : #include "pim_rpf.h"
      42             : #include "pim_rp.h"
      43             : #include "pim_jp_agg.h"
      44             : #include "pim_util.h"
      45             : #include "pim_ssm.h"
      46             : 
      47           0 : static void on_trace(const char *label, struct interface *ifp, pim_addr src)
      48             : {
      49           0 :         if (PIM_DEBUG_PIM_TRACE)
      50           0 :                 zlog_debug("%s: from %pPA on %s", label, &src, ifp->name);
      51           0 : }
      52             : 
      53           0 : static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
      54             :                       uint16_t holdtime, pim_addr upstream, pim_sgaddr *sg,
      55             :                       uint8_t source_flags)
      56             : {
      57           0 :         struct pim_interface *pim_ifp = NULL;
      58             : 
      59           0 :         if (PIM_DEBUG_PIM_TRACE)
      60           0 :                 zlog_debug(
      61             :                         "%s: join (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s",
      62             :                         __func__, sg, !!(source_flags & PIM_RPT_BIT_MASK),
      63             :                         !!(source_flags & PIM_WILDCARD_BIT_MASK), &upstream,
      64             :                         holdtime, &neigh->source_addr, ifp->name);
      65             : 
      66           0 :         pim_ifp = ifp->info;
      67           0 :         assert(pim_ifp);
      68             : 
      69           0 :         ++pim_ifp->pim_ifstat_join_recv;
      70             : 
      71             :         /*
      72             :          * If the RPT and WC are set it's a (*,G)
      73             :          * and the source is the RP
      74             :          */
      75           0 :         if (CHECK_FLAG(source_flags, PIM_WILDCARD_BIT_MASK)) {
      76             :                 /* As per RFC 7761 Section 4.9.1:
      77             :                  * The RPT (or Rendezvous Point Tree) bit is a 1-bit value for
      78             :                  * use with PIM Join/Prune messages (see Section 4.9.5.1). If
      79             :                  * the WC bit is 1, the RPT bit MUST be 1.
      80             :                  */
      81           0 :                 if (!CHECK_FLAG(source_flags, PIM_RPT_BIT_MASK)) {
      82           0 :                         if (PIM_DEBUG_PIM_J_P)
      83           0 :                                 zlog_debug(
      84             :                                         "Discarding (*,G)=%pSG join since WC bit is set but RPT bit is unset",
      85             :                                         sg);
      86             : 
      87           0 :                         return;
      88             :                 }
      89             : 
      90           0 :                 struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp);
      91           0 :                 pim_addr rpf_addr;
      92             : 
      93           0 :                 if (!rp) {
      94           0 :                         zlog_warn("%s: Lookup of RP failed for %pSG", __func__,
      95             :                                   sg);
      96           0 :                         return;
      97             :                 }
      98             :                 /*
      99             :                  * If the RP sent in the message is not
     100             :                  * our RP for the group, drop the message
     101             :                  */
     102           0 :                 rpf_addr = rp->rpf_addr;
     103           0 :                 if (pim_addr_cmp(sg->src, rpf_addr)) {
     104           0 :                         zlog_warn(
     105             :                                 "%s: Specified RP(%pPAs) in join is different than our configured RP(%pPAs)",
     106             :                                 __func__, &sg->src, &rpf_addr);
     107           0 :                         return;
     108             :                 }
     109             : 
     110           0 :                 if (pim_is_grp_ssm(pim_ifp->pim, sg->grp)) {
     111           0 :                         zlog_warn(
     112             :                                 "%s: Specified Group(%pPA) in join is now in SSM, not allowed to create PIM state",
     113             :                                 __func__, &sg->grp);
     114           0 :                         return;
     115             :                 }
     116             : 
     117           0 :                 sg->src = PIMADDR_ANY;
     118             :         }
     119             : 
     120             :         /* Restart join expiry timer */
     121           0 :         pim_ifchannel_join_add(ifp, neigh->source_addr, upstream, sg,
     122             :                                source_flags, holdtime);
     123             : }
     124             : 
     125           0 : static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh,
     126             :                        uint16_t holdtime, pim_addr upstream, pim_sgaddr *sg,
     127             :                        uint8_t source_flags)
     128             : {
     129           0 :         struct pim_interface *pim_ifp = NULL;
     130             : 
     131           0 :         if (PIM_DEBUG_PIM_TRACE)
     132           0 :                 zlog_debug(
     133             :                         "%s: prune (S,G)=%pSG rpt=%d wc=%d upstream=%pPAs holdtime=%d from %pPA on %s",
     134             :                         __func__, sg, source_flags & PIM_RPT_BIT_MASK,
     135             :                         source_flags & PIM_WILDCARD_BIT_MASK, &upstream,
     136             :                         holdtime, &neigh->source_addr, ifp->name);
     137             : 
     138           0 :         pim_ifp = ifp->info;
     139           0 :         assert(pim_ifp);
     140             : 
     141           0 :         ++pim_ifp->pim_ifstat_prune_recv;
     142             : 
     143           0 :         if (CHECK_FLAG(source_flags, PIM_WILDCARD_BIT_MASK)) {
     144             :                 /* As per RFC 7761 Section 4.9.1:
     145             :                  * The RPT (or Rendezvous Point Tree) bit is a 1-bit value for
     146             :                  * use with PIM Join/Prune messages (see Section 4.9.5.1). If
     147             :                  * the WC bit is 1, the RPT bit MUST be 1.
     148             :                  */
     149           0 :                 if (!CHECK_FLAG(source_flags, PIM_RPT_BIT_MASK)) {
     150           0 :                         if (PIM_DEBUG_PIM_J_P)
     151           0 :                                 zlog_debug(
     152             :                                         "Discarding (*,G)=%pSG prune since WC bit is set but RPT bit is unset",
     153             :                                         sg);
     154             : 
     155           0 :                         return;
     156             :                 }
     157             : 
     158             :                 /*
     159             :                  * RFC 4601 Section 4.5.2:
     160             :                  * Received Prune(*,G) messages are processed even if the
     161             :                  * RP in the message does not match RP(G).
     162             :                  */
     163           0 :                 if (PIM_DEBUG_PIM_TRACE)
     164           0 :                         zlog_debug("%s: Prune received with RP(%pPAs) for %pSG",
     165             :                                    __func__, &sg->src, sg);
     166             : 
     167           0 :                 sg->src = PIMADDR_ANY;
     168             :         }
     169             : 
     170           0 :         pim_ifchannel_prune(ifp, upstream, sg, source_flags, holdtime);
     171             : }
     172             : 
     173           0 : int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh,
     174             :                        pim_addr src_addr, uint8_t *tlv_buf, int tlv_buf_size)
     175             : {
     176           0 :         pim_addr msg_upstream_addr;
     177           0 :         bool wrong_af = false;
     178           0 :         struct pim_interface *pim_ifp;
     179           0 :         uint8_t msg_num_groups;
     180           0 :         uint16_t msg_holdtime;
     181           0 :         int addr_offset;
     182           0 :         uint8_t *buf;
     183           0 :         uint8_t *pastend;
     184           0 :         int remain;
     185           0 :         int group;
     186           0 :         struct pim_ifchannel *child = NULL;
     187           0 :         struct listnode *ch_node, *nch_node;
     188             : 
     189           0 :         buf = tlv_buf;
     190           0 :         pastend = tlv_buf + tlv_buf_size;
     191           0 :         pim_ifp = ifp->info;
     192             : 
     193           0 :         if (pim_ifp->pim_passive_enable) {
     194           0 :                 if (PIM_DEBUG_PIM_PACKETS)
     195           0 :                         zlog_debug(
     196             :                                 "skip receiving PIM message on passive interface %s",
     197             :                                 ifp->name);
     198           0 :                 return 0;
     199             :         }
     200             : 
     201             :         /*
     202             :           Parse ucast addr
     203             :         */
     204           0 :         addr_offset = pim_parse_addr_ucast(&msg_upstream_addr, buf,
     205             :                                            pastend - buf, &wrong_af);
     206           0 :         if (addr_offset < 1) {
     207           0 :                 zlog_warn("%s: pim_parse_addr_ucast() failure: from %pPA on %s",
     208             :                           __func__, &src_addr, ifp->name);
     209           0 :                 return -1;
     210             :         }
     211           0 :         buf += addr_offset;
     212             : 
     213             :         /*
     214             :           Check upstream address family
     215             :          */
     216           0 :         if (wrong_af) {
     217           0 :                 zlog_warn(
     218             :                         "%s: ignoring join/prune directed to unexpected addr family from %pPA on %s",
     219             :                         __func__, &src_addr, ifp->name);
     220           0 :                 return -2;
     221             :         }
     222             : 
     223           0 :         remain = pastend - buf;
     224           0 :         if (remain < 4) {
     225           0 :                 zlog_warn(
     226             :                         "%s: short join/prune message buffer for group list: size=%d minimum=%d from %pPA on %s",
     227             :                         __func__, remain, 4, &src_addr, ifp->name);
     228           0 :                 return -4;
     229             :         }
     230             : 
     231           0 :         ++buf; /* skip reserved byte */
     232           0 :         msg_num_groups = *(const uint8_t *)buf;
     233           0 :         ++buf;
     234           0 :         msg_holdtime = ntohs(*(const uint16_t *)buf);
     235           0 :         ++buf;
     236           0 :         ++buf;
     237             : 
     238           0 :         if (PIM_DEBUG_PIM_J_P)
     239           0 :                 zlog_debug(
     240             :                         "%s: join/prune upstream=%pPAs groups=%d holdtime=%d from %pPA on %s",
     241             :                         __func__, &msg_upstream_addr, msg_num_groups,
     242             :                         msg_holdtime, &src_addr, ifp->name);
     243             : 
     244             :         /* Scan groups */
     245           0 :         for (group = 0; group < msg_num_groups; ++group) {
     246           0 :                 pim_sgaddr sg;
     247           0 :                 uint8_t msg_source_flags;
     248           0 :                 uint16_t msg_num_joined_sources;
     249           0 :                 uint16_t msg_num_pruned_sources;
     250           0 :                 int source;
     251           0 :                 struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL;
     252           0 :                 bool filtered = false;
     253             : 
     254           0 :                 memset(&sg, 0, sizeof(sg));
     255           0 :                 addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf);
     256           0 :                 if (addr_offset < 1) {
     257           0 :                         return -5;
     258             :                 }
     259           0 :                 buf += addr_offset;
     260             : 
     261           0 :                 remain = pastend - buf;
     262           0 :                 if (remain < 4) {
     263           0 :                         zlog_warn(
     264             :                                 "%s: short join/prune buffer for source list: size=%d minimum=%d from %pPA on %s",
     265             :                                 __func__, remain, 4, &src_addr, ifp->name);
     266           0 :                         return -6;
     267             :                 }
     268             : 
     269           0 :                 msg_num_joined_sources = ntohs(*(const uint16_t *)buf);
     270           0 :                 buf += 2;
     271           0 :                 msg_num_pruned_sources = ntohs(*(const uint16_t *)buf);
     272           0 :                 buf += 2;
     273             : 
     274           0 :                 if (PIM_DEBUG_PIM_J_P)
     275           0 :                         zlog_debug(
     276             :                                 "%s: join/prune upstream=%pPAs group=%pPA/32 join_src=%d prune_src=%d from %pPA on %s",
     277             :                                 __func__, &msg_upstream_addr, &sg.grp,
     278             :                                 msg_num_joined_sources, msg_num_pruned_sources,
     279             :                                 &src_addr, ifp->name);
     280             : 
     281             :                 /* boundary check */
     282           0 :                 filtered = pim_is_group_filtered(pim_ifp, &sg.grp);
     283             : 
     284             :                 /* Scan joined sources */
     285           0 :                 for (source = 0; source < msg_num_joined_sources; ++source) {
     286           0 :                         addr_offset = pim_parse_addr_source(
     287           0 :                                 &sg, &msg_source_flags, buf, pastend - buf);
     288           0 :                         if (addr_offset < 1) {
     289             :                                 return -7;
     290             :                         }
     291             : 
     292           0 :                         buf += addr_offset;
     293             : 
     294             :                         /* if we are filtering this group, skip the join */
     295           0 :                         if (filtered)
     296           0 :                                 continue;
     297             : 
     298           0 :                         recv_join(ifp, neigh, msg_holdtime, msg_upstream_addr,
     299             :                                   &sg, msg_source_flags);
     300             : 
     301           0 :                         if (pim_addr_is_any(sg.src)) {
     302           0 :                                 starg_ch = pim_ifchannel_find(ifp, &sg);
     303           0 :                                 if (starg_ch)
     304           0 :                                         pim_ifchannel_set_star_g_join_state(
     305             :                                                 starg_ch, 0, 1);
     306             :                         }
     307             :                 }
     308             : 
     309             :                 /* Scan pruned sources */
     310           0 :                 for (source = 0; source < msg_num_pruned_sources; ++source) {
     311           0 :                         addr_offset = pim_parse_addr_source(
     312           0 :                                 &sg, &msg_source_flags, buf, pastend - buf);
     313           0 :                         if (addr_offset < 1) {
     314             :                                 return -8;
     315             :                         }
     316             : 
     317           0 :                         buf += addr_offset;
     318             : 
     319             :                         /* if we are filtering this group, skip the prune */
     320           0 :                         if (filtered)
     321           0 :                                 continue;
     322             : 
     323           0 :                         recv_prune(ifp, neigh, msg_holdtime, msg_upstream_addr,
     324             :                                    &sg, msg_source_flags);
     325             :                         /*
     326             :                          * So if we are receiving a S,G,RPT prune
     327             :                          * before we have any data for that S,G
     328             :                          * We need to retrieve the sg_ch after
     329             :                          * we parse the prune.
     330             :                          */
     331           0 :                         sg_ch = pim_ifchannel_find(ifp, &sg);
     332             : 
     333           0 :                         if (!sg_ch)
     334           0 :                                 continue;
     335             : 
     336             :                         /* (*,G) prune received */
     337           0 :                         for (ALL_LIST_ELEMENTS(sg_ch->sources, ch_node,
     338             :                                                nch_node, child)) {
     339           0 :                                 if (PIM_IF_FLAG_TEST_S_G_RPT(child->flags)) {
     340           0 :                                         if (child->ifjoin_state
     341             :                                             == PIM_IFJOIN_PRUNE_PENDING_TMP)
     342           0 :                                                 THREAD_OFF(
     343             :                                                         child->t_ifjoin_prune_pending_timer);
     344           0 :                                         THREAD_OFF(
     345             :                                                 child->t_ifjoin_expiry_timer);
     346           0 :                                         PIM_IF_FLAG_UNSET_S_G_RPT(child->flags);
     347           0 :                                         child->ifjoin_state = PIM_IFJOIN_NOINFO;
     348           0 :                                         delete_on_noinfo(child);
     349             :                                 }
     350             :                         }
     351             : 
     352             :                         /* Received SG-RPT Prune delete oif from specific S,G */
     353           0 :                         if (starg_ch && (msg_source_flags & PIM_RPT_BIT_MASK)
     354           0 :                             && !(msg_source_flags & PIM_WILDCARD_BIT_MASK)) {
     355           0 :                                 struct pim_upstream *up = sg_ch->upstream;
     356           0 :                                 PIM_IF_FLAG_SET_S_G_RPT(sg_ch->flags);
     357           0 :                                 if (up) {
     358           0 :                                         if (PIM_DEBUG_PIM_TRACE)
     359           0 :                                                 zlog_debug(
     360             :                                                         "%s: SGRpt flag is set, del inherit oif from up %s",
     361             :                                                         __func__, up->sg_str);
     362           0 :                                         pim_channel_del_inherited_oif(
     363             :                                                 up->channel_oil,
     364             :                                                 starg_ch->interface,
     365             :                                                 __func__);
     366             :                                 }
     367             :                         }
     368             :                 }
     369           0 :                 if (starg_ch && !filtered)
     370           0 :                         pim_ifchannel_set_star_g_join_state(starg_ch, 1, 0);
     371           0 :                 starg_ch = NULL;
     372             :         } /* scan groups */
     373             : 
     374             :         return 0;
     375             : }
     376             : 
     377             : /*
     378             :  * J/P Message Format
     379             :  *
     380             :  * While the RFC clearly states that this is 32 bits wide, it
     381             :  * is cheating.  These fields:
     382             :  * Encoded-Unicast format   (6 bytes MIN)
     383             :  * Encoded-Group format     (8 bytes MIN)
     384             :  * Encoded-Source format    (8 bytes MIN)
     385             :  * are *not* 32 bits wide.
     386             :  *
     387             :  * Nor does the RFC explicitly call out the size for:
     388             :  * Reserved                 (1 byte)
     389             :  * Num Groups               (1 byte)
     390             :  * Holdtime                 (2 bytes)
     391             :  * Number of Joined Sources (2 bytes)
     392             :  * Number of Pruned Sources (2 bytes)
     393             :  *
     394             :  * This leads to a missleading representation from casual
     395             :  * reading and making assumptions.  Be careful!
     396             :  *
     397             :  *   0                   1                   2                   3
     398             :  *   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     399             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     400             :  *  |PIM Ver| Type  |   Reserved    |           Checksum            |
     401             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     402             :  *  |        Upstream Neighbor Address (Encoded-Unicast format)     |
     403             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     404             :  *  |  Reserved     | Num groups    |          Holdtime             |
     405             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     406             :  *  |         Multicast Group Address 1 (Encoded-Group format)      |
     407             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     408             :  *  |   Number of Joined Sources    |   Number of Pruned Sources    |
     409             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     410             :  *  |        Joined Source Address 1 (Encoded-Source format)        |
     411             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     412             :  *  |                             .                                 |
     413             :  *  |                             .                                 |
     414             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     415             :  *  |        Joined Source Address n (Encoded-Source format)        |
     416             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     417             :  *  |        Pruned Source Address 1 (Encoded-Source format)        |
     418             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     419             :  *  |                             .                                 |
     420             :  *  |                             .                                 |
     421             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     422             :  *  |        Pruned Source Address n (Encoded-Source format)        |
     423             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     424             :  *  |         Multicast Group Address m (Encoded-Group format)      |
     425             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     426             :  *  |   Number of Joined Sources    |   Number of Pruned Sources    |
     427             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     428             :  *  |        Joined Source Address 1 (Encoded-Source format)        |
     429             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     430             :  *  |                             .                                 |
     431             :  *  |                             .                                 |
     432             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     433             :  *  |        Joined Source Address n (Encoded-Source format)        |
     434             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     435             :  *  |        Pruned Source Address 1 (Encoded-Source format)        |
     436             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     437             :  *  |                             .                                 |
     438             :  *  |                             .                                 |
     439             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     440             :  *  |        Pruned Source Address n (Encoded-Source format)        |
     441             :  *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     442             :  */
     443           0 : int pim_joinprune_send(struct pim_rpf *rpf, struct list *groups)
     444             : {
     445           0 :         struct pim_jp_agg_group *group;
     446           0 :         struct pim_interface *pim_ifp = NULL;
     447           0 :         struct pim_jp_groups *grp = NULL;
     448           0 :         struct pim_jp *msg = NULL;
     449           0 :         struct listnode *node, *nnode;
     450           0 :         uint8_t pim_msg[10000];
     451           0 :         uint8_t *curr_ptr = pim_msg;
     452           0 :         bool new_packet = true;
     453           0 :         size_t packet_left = 0;
     454           0 :         size_t packet_size = 0;
     455           0 :         size_t group_size = 0;
     456             : 
     457           0 :         if (rpf->source_nexthop.interface)
     458           0 :                 pim_ifp = rpf->source_nexthop.interface->info;
     459             :         else {
     460           0 :                 zlog_warn("%s: RPF interface is not present", __func__);
     461           0 :                 return -1;
     462             :         }
     463             : 
     464             : 
     465           0 :         on_trace(__func__, rpf->source_nexthop.interface, rpf->rpf_addr);
     466             : 
     467           0 :         if (!pim_ifp) {
     468           0 :                 zlog_warn("%s: multicast not enabled on interface %s", __func__,
     469             :                           rpf->source_nexthop.interface->name);
     470           0 :                 return -1;
     471             :         }
     472             : 
     473           0 :         if (pim_addr_is_any(rpf->rpf_addr)) {
     474           0 :                 if (PIM_DEBUG_PIM_J_P)
     475           0 :                         zlog_debug(
     476             :                                 "%s: upstream=%pPA is myself on interface %s",
     477             :                                 __func__, &rpf->rpf_addr,
     478             :                                 rpf->source_nexthop.interface->name);
     479           0 :                 return 0;
     480             :         }
     481             : 
     482             :         /*
     483             :           RFC 4601: 4.3.1.  Sending Hello Messages
     484             : 
     485             :           Thus, if a router needs to send a Join/Prune or Assert message on
     486             :           an interface on which it has not yet sent a Hello message with the
     487             :           currently configured IP address, then it MUST immediately send the
     488             :           relevant Hello message without waiting for the Hello Timer to
     489             :           expire, followed by the Join/Prune or Assert message.
     490             :         */
     491           0 :         pim_hello_require(rpf->source_nexthop.interface);
     492             : 
     493           0 :         for (ALL_LIST_ELEMENTS(groups, node, nnode, group)) {
     494           0 :                 if (new_packet) {
     495           0 :                         msg = (struct pim_jp *)pim_msg;
     496             : 
     497           0 :                         memset(msg, 0, sizeof(*msg));
     498             : 
     499           0 :                         pim_msg_addr_encode_ucast((uint8_t *)&msg->addr,
     500             :                                                   rpf->rpf_addr);
     501           0 :                         msg->reserved = 0;
     502           0 :                         msg->holdtime = htons(PIM_JP_HOLDTIME);
     503             : 
     504           0 :                         new_packet = false;
     505             : 
     506           0 :                         grp = &msg->groups[0];
     507           0 :                         curr_ptr = (uint8_t *)grp;
     508           0 :                         packet_size = sizeof(struct pim_msg_header);
     509           0 :                         packet_size += sizeof(pim_encoded_unicast);
     510           0 :                         packet_size +=
     511             :                                 4; // reserved (1) + groups (1) + holdtime (2)
     512             : 
     513           0 :                         packet_left = rpf->source_nexthop.interface->mtu - 24;
     514           0 :                         packet_left -= packet_size;
     515             :                 }
     516           0 :                 if (PIM_DEBUG_PIM_J_P)
     517           0 :                         zlog_debug(
     518             :                                 "%s: sending (G)=%pPAs to upstream=%pPA on interface %s",
     519             :                                 __func__, &group->group, &rpf->rpf_addr,
     520             :                                 rpf->source_nexthop.interface->name);
     521             : 
     522           0 :                 group_size = pim_msg_get_jp_group_size(group->sources);
     523           0 :                 if (group_size > packet_left) {
     524           0 :                         pim_msg_build_header(pim_ifp->primary_address,
     525             :                                              qpim_all_pim_routers_addr, pim_msg,
     526             :                                              packet_size,
     527             :                                              PIM_MSG_TYPE_JOIN_PRUNE, false);
     528           0 :                         if (pim_msg_send(pim_ifp->pim_sock_fd,
     529             :                                          pim_ifp->primary_address,
     530             :                                          qpim_all_pim_routers_addr, pim_msg,
     531             :                                          packet_size,
     532             :                                          rpf->source_nexthop.interface)) {
     533           0 :                                 zlog_warn(
     534             :                                         "%s: could not send PIM message on interface %s",
     535             :                                         __func__,
     536             :                                         rpf->source_nexthop.interface->name);
     537             :                         }
     538             : 
     539           0 :                         msg = (struct pim_jp *)pim_msg;
     540           0 :                         memset(msg, 0, sizeof(*msg));
     541             : 
     542           0 :                         pim_msg_addr_encode_ucast((uint8_t *)&msg->addr,
     543             :                                                   rpf->rpf_addr);
     544           0 :                         msg->reserved = 0;
     545           0 :                         msg->holdtime = htons(PIM_JP_HOLDTIME);
     546             : 
     547           0 :                         new_packet = false;
     548             : 
     549           0 :                         grp = &msg->groups[0];
     550           0 :                         curr_ptr = (uint8_t *)grp;
     551           0 :                         packet_size = sizeof(struct pim_msg_header);
     552           0 :                         packet_size += sizeof(pim_encoded_unicast);
     553           0 :                         packet_size +=
     554             :                                 4; // reserved (1) + groups (1) + holdtime (2)
     555             : 
     556           0 :                         packet_left = rpf->source_nexthop.interface->mtu - 24;
     557           0 :                         packet_left -= packet_size;
     558             :                 }
     559             : 
     560           0 :                 msg->num_groups++;
     561             :                 /*
     562             :                   Build PIM message
     563             :                 */
     564             : 
     565           0 :                 curr_ptr += group_size;
     566           0 :                 packet_left -= group_size;
     567           0 :                 packet_size += group_size;
     568           0 :                 pim_msg_build_jp_groups(grp, group, group_size);
     569             : 
     570           0 :                 if (!pim_ifp->pim_passive_enable) {
     571           0 :                         pim_ifp->pim_ifstat_join_send += ntohs(grp->joins);
     572           0 :                         pim_ifp->pim_ifstat_prune_send += ntohs(grp->prunes);
     573             :                 }
     574             : 
     575           0 :                 if (PIM_DEBUG_PIM_TRACE)
     576           0 :                         zlog_debug(
     577             :                                 "%s: interface %s num_joins %u num_prunes %u",
     578             :                                 __func__, rpf->source_nexthop.interface->name,
     579             :                                 ntohs(grp->joins), ntohs(grp->prunes));
     580             : 
     581           0 :                 grp = (struct pim_jp_groups *)curr_ptr;
     582           0 :                 if (packet_left < sizeof(struct pim_jp_groups)
     583           0 :                     || msg->num_groups == 255) {
     584           0 :                         pim_msg_build_header(pim_ifp->primary_address,
     585             :                                              qpim_all_pim_routers_addr, pim_msg,
     586             :                                              packet_size,
     587             :                                              PIM_MSG_TYPE_JOIN_PRUNE, false);
     588           0 :                         if (pim_msg_send(pim_ifp->pim_sock_fd,
     589             :                                          pim_ifp->primary_address,
     590             :                                          qpim_all_pim_routers_addr, pim_msg,
     591             :                                          packet_size,
     592             :                                          rpf->source_nexthop.interface)) {
     593           0 :                                 zlog_warn(
     594             :                                         "%s: could not send PIM message on interface %s",
     595             :                                         __func__,
     596             :                                         rpf->source_nexthop.interface->name);
     597             :                         }
     598             : 
     599             :                         new_packet = true;
     600             :                 }
     601             :         }
     602             : 
     603             : 
     604           0 :         if (!new_packet) {
     605             :                 // msg->num_groups = htons (msg->num_groups);
     606           0 :                 pim_msg_build_header(
     607             :                         pim_ifp->primary_address, qpim_all_pim_routers_addr,
     608             :                         pim_msg, packet_size, PIM_MSG_TYPE_JOIN_PRUNE, false);
     609           0 :                 if (pim_msg_send(pim_ifp->pim_sock_fd, pim_ifp->primary_address,
     610             :                                  qpim_all_pim_routers_addr, pim_msg,
     611             :                                  packet_size, rpf->source_nexthop.interface)) {
     612           0 :                         zlog_warn(
     613             :                                 "%s: could not send PIM message on interface %s",
     614             :                                 __func__, rpf->source_nexthop.interface->name);
     615             :                 }
     616             :         }
     617             :         return 0;
     618             : }

Generated by: LCOV version v1.16-topotato