Coverage Report

Created: 2025-12-12 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/pimd/pim_mroute.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * PIM for Quagga
4
 * Copyright (C) 2008  Everton da Silva Marques
5
 */
6
7
#include <zebra.h>
8
#include "log.h"
9
#include "privs.h"
10
#include "if.h"
11
#include "prefix.h"
12
#include "vty.h"
13
#include "plist.h"
14
#include "sockopt.h"
15
#include "lib_errors.h"
16
#include "lib/network.h"
17
18
#include "pimd.h"
19
#include "pim_rpf.h"
20
#include "pim_mroute.h"
21
#include "pim_oil.h"
22
#include "pim_str.h"
23
#include "pim_time.h"
24
#include "pim_iface.h"
25
#include "pim_macro.h"
26
#include "pim_rp.h"
27
#include "pim_oil.h"
28
#include "pim_register.h"
29
#include "pim_ifchannel.h"
30
#include "pim_zlookup.h"
31
#include "pim_ssm.h"
32
#include "pim_sock.h"
33
#include "pim_vxlan.h"
34
#include "pim_msg.h"
35
36
static void mroute_read_on(struct pim_instance *pim);
37
static int pim_upstream_mroute_update(struct channel_oil *c_oil,
38
              const char *name);
39
40
int pim_mroute_set(struct pim_instance *pim, int enable)
41
0
{
42
0
  int err;
43
0
  int opt, data;
44
0
  socklen_t data_len = sizeof(data);
45
46
  /*
47
   * We need to create the VRF table for the pim mroute_socket
48
   */
49
0
  if (enable && pim->vrf->vrf_id != VRF_DEFAULT) {
50
0
    frr_with_privs (&pimd_privs) {
51
52
0
      data = pim->vrf->data.l.table_id;
53
0
      err = setsockopt(pim->mroute_socket, PIM_IPPROTO,
54
0
           MRT_TABLE, &data, data_len);
55
0
      if (err) {
56
0
        zlog_warn(
57
0
          "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO, MRT_TABLE=%d): errno=%d: %s",
58
0
          __FILE__, __func__, pim->mroute_socket,
59
0
          data, errno, safe_strerror(errno));
60
0
        return -1;
61
0
      }
62
0
    }
63
0
  }
64
65
0
  frr_with_privs (&pimd_privs) {
66
0
    opt = enable ? MRT_INIT : MRT_DONE;
67
    /*
68
     * *BSD *cares* about what value we pass down
69
     * here
70
     */
71
0
    data = 1;
72
0
    err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &data,
73
0
         data_len);
74
0
    if (err) {
75
0
      zlog_warn(
76
0
        "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,%s=%d): errno=%d: %s",
77
0
        __FILE__, __func__, pim->mroute_socket,
78
0
        enable ? "MRT_INIT" : "MRT_DONE", data, errno,
79
0
        safe_strerror(errno));
80
0
      return -1;
81
0
    }
82
0
  }
83
84
0
#if defined(HAVE_IP_PKTINFO)
85
0
  if (enable) {
86
    /* Linux and Solaris IP_PKTINFO */
87
0
    data = 1;
88
0
    if (setsockopt(pim->mroute_socket, PIM_IPPROTO, IP_PKTINFO,
89
0
             &data, data_len)) {
90
0
      zlog_warn(
91
0
        "Could not set IP_PKTINFO on socket fd=%d: errno=%d: %s",
92
0
        pim->mroute_socket, errno,
93
0
        safe_strerror(errno));
94
0
    }
95
0
  }
96
0
#endif
97
98
#if PIM_IPV == 6
99
  if (enable) {
100
    /* Linux and Solaris IPV6_PKTINFO */
101
    data = 1;
102
    if (setsockopt(pim->mroute_socket, PIM_IPPROTO,
103
             IPV6_RECVPKTINFO, &data, data_len)) {
104
      zlog_warn(
105
        "Could not set IPV6_RECVPKTINFO on socket fd=%d: errno=%d: %s",
106
        pim->mroute_socket, errno,
107
        safe_strerror(errno));
108
    }
109
  }
110
#endif
111
0
  setsockopt_so_recvbuf(pim->mroute_socket, 1024 * 1024 * 8);
112
113
0
  if (set_nonblocking(pim->mroute_socket) < 0) {
114
0
    zlog_warn(
115
0
      "Could not set non blocking on socket fd=%d: errno=%d: %s",
116
0
      pim->mroute_socket, errno, safe_strerror(errno));
117
0
    return -1;
118
0
  }
119
120
0
  if (enable) {
121
0
#if defined linux
122
0
    int upcalls = GMMSG_WRVIFWHOLE;
123
0
    opt = MRT_PIM;
124
125
0
    err = setsockopt(pim->mroute_socket, PIM_IPPROTO, opt, &upcalls,
126
0
         sizeof(upcalls));
127
0
    if (err) {
128
0
      zlog_warn(
129
0
        "Failure to register for VIFWHOLE and WRONGVIF upcalls %d %s",
130
0
        errno, safe_strerror(errno));
131
0
      return -1;
132
0
    }
133
#else
134
    zlog_warn(
135
      "PIM-SM will not work properly on this platform, until the ability to receive the WRVIFWHOLE upcall");
136
#endif
137
0
  }
138
139
0
  return 0;
140
0
}
141
142
static const char *const gmmsgtype2str[GMMSG_WRVIFWHOLE + 1] = {
143
  "<unknown_upcall?>", "NOCACHE", "WRONGVIF", "WHOLEPKT", "WRVIFWHOLE"};
144
145
146
int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg)
147
0
{
148
0
  struct pim_interface *pim_ifp = ifp->info;
149
0
  struct pim_upstream *up;
150
0
  pim_sgaddr sg;
151
0
  bool desync = false;
152
153
0
  memset(&sg, 0, sizeof(sg));
154
0
  sg.src = msg->msg_im_src;
155
0
  sg.grp = msg->msg_im_dst;
156
157
158
0
  if (!pim_ifp || !pim_ifp->pim_enable) {
159
0
    if (PIM_DEBUG_MROUTE)
160
0
      zlog_debug(
161
0
        "%s: %s on interface, dropping packet to %pSG",
162
0
        ifp->name,
163
0
        !pim_ifp ? "Multicast not enabled"
164
0
           : "PIM not enabled",
165
0
        &sg);
166
0
    return 0;
167
0
  }
168
169
0
  if (!pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
170
    /* for ASM, check that we have enough information (i.e. path
171
     * to RP) to make a decision on what to do with this packet.
172
     *
173
     * for SSM, this is meaningless, everything is join-driven,
174
     * and for NOCACHE we need to install an empty OIL MFC entry
175
     * so the kernel doesn't keep nagging us.
176
     */
177
0
    struct pim_rpf *rpg;
178
179
0
    rpg = RP(pim_ifp->pim, msg->msg_im_dst);
180
0
    if (!rpg) {
181
0
      if (PIM_DEBUG_MROUTE)
182
0
        zlog_debug("%s: no RPF for packet to %pSG",
183
0
             ifp->name, &sg);
184
0
      return 0;
185
0
    }
186
0
    if (pim_rpf_addr_is_inaddr_any(rpg)) {
187
0
      if (PIM_DEBUG_MROUTE)
188
0
        zlog_debug("%s: null RPF for packet to %pSG",
189
0
             ifp->name, &sg);
190
0
      return 0;
191
0
    }
192
0
  }
193
194
  /*
195
   * If we've received a multicast packet that isn't connected to
196
   * us
197
   */
198
0
  if (!pim_if_connected_to_source(ifp, msg->msg_im_src)) {
199
0
    if (PIM_DEBUG_MROUTE)
200
0
      zlog_debug(
201
0
        "%s: incoming packet to %pSG from non-connected source",
202
0
        ifp->name, &sg);
203
0
    return 0;
204
0
  }
205
206
0
  if (!(PIM_I_am_DR(pim_ifp))) {
207
    /* unlike the other debug messages, this one is further in the
208
     * "normal operation" category and thus under _DETAIL
209
     */
210
0
    if (PIM_DEBUG_MROUTE_DETAIL)
211
0
      zlog_debug(
212
0
        "%s: not DR on interface, not forwarding traffic for %pSG",
213
0
        ifp->name, &sg);
214
215
    /*
216
     * We are not the DR, but we are still receiving packets
217
     * Let's blackhole those packets for the moment
218
     * As that they will be coming up to the cpu
219
     * and causing us to consider them.
220
     *
221
     * This *will* create a dangling channel_oil
222
     * that I see no way to get rid of.  Just noting
223
     * this for future reference.
224
     */
225
0
    up = pim_upstream_find_or_add(
226
0
      &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE, __func__);
227
0
    pim_upstream_mroute_add(up->channel_oil, __func__);
228
229
0
    return 0;
230
0
  }
231
232
0
  up = pim_upstream_find_or_add(&sg, ifp, PIM_UPSTREAM_FLAG_MASK_FHR,
233
0
              __func__);
234
0
  if (up->channel_oil->installed) {
235
0
    zlog_warn(
236
0
      "%s: NOCACHE for %pSG, MFC entry disappeared - reinstalling",
237
0
      ifp->name, &sg);
238
0
    desync = true;
239
0
  }
240
241
  /*
242
   * I moved this debug till after the actual add because
243
   * I want to take advantage of the up->sg_str being filled in.
244
   */
245
0
  if (PIM_DEBUG_MROUTE) {
246
0
    zlog_debug("%s: Adding a Route %s for WHOLEPKT consumption",
247
0
         __func__, up->sg_str);
248
0
  }
249
250
0
  PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
251
0
  pim_upstream_keep_alive_timer_start(up, pim_ifp->pim->keep_alive_time);
252
253
0
  up->channel_oil->cc.pktcnt++;
254
  // resolve mfcc_parent prior to mroute_add in channel_add_oif
255
0
  if (up->rpf.source_nexthop.interface &&
256
0
      *oil_parent(up->channel_oil) >= MAXVIFS) {
257
0
    pim_upstream_mroute_iif_update(up->channel_oil, __func__);
258
0
  }
259
0
  pim_register_join(up);
260
  /* if we have receiver, inherit from parent */
261
0
  pim_upstream_inherited_olist_decide(pim_ifp->pim, up);
262
263
  /* we just got NOCACHE from the kernel, so...  MFC is not in the
264
   * kernel for some reason or another.  Try installing again.
265
   */
266
0
  if (desync)
267
0
    pim_upstream_mroute_update(up->channel_oil, __func__);
268
0
  return 0;
269
0
}
270
271
int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const char *buf,
272
          size_t len)
273
0
{
274
0
  struct pim_interface *pim_ifp;
275
0
  pim_sgaddr sg;
276
0
  struct pim_rpf *rpg;
277
0
  const ipv_hdr *ip_hdr;
278
0
  struct pim_upstream *up;
279
280
0
  pim_ifp = ifp->info;
281
282
0
  ip_hdr = (const ipv_hdr *)buf;
283
284
0
  memset(&sg, 0, sizeof(sg));
285
0
  sg.src = IPV_SRC(ip_hdr);
286
0
  sg.grp = IPV_DST(ip_hdr);
287
288
0
  up = pim_upstream_find(pim_ifp->pim, &sg);
289
0
  if (!up) {
290
0
    pim_sgaddr star = sg;
291
0
    star.src = PIMADDR_ANY;
292
293
0
    up = pim_upstream_find(pim_ifp->pim, &star);
294
295
0
    if (up && PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) {
296
0
      up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
297
0
                PIM_UPSTREAM_FLAG_MASK_SRC_LHR,
298
0
                __func__, NULL);
299
0
      if (!up) {
300
0
        if (PIM_DEBUG_MROUTE)
301
0
          zlog_debug(
302
0
            "%s: Unable to create upstream information for %pSG",
303
0
            __func__, &sg);
304
0
        return 0;
305
0
      }
306
0
      pim_upstream_keep_alive_timer_start(
307
0
        up, pim_ifp->pim->keep_alive_time);
308
0
      pim_upstream_inherited_olist(pim_ifp->pim, up);
309
0
      pim_upstream_update_join_desired(pim_ifp->pim, up);
310
311
0
      if (PIM_DEBUG_MROUTE)
312
0
        zlog_debug("%s: Creating %s upstream on LHR",
313
0
             __func__, up->sg_str);
314
0
      return 0;
315
0
    }
316
0
    if (PIM_DEBUG_MROUTE_DETAIL) {
317
0
      zlog_debug(
318
0
        "%s: Unable to find upstream channel WHOLEPKT%pSG",
319
0
        __func__, &sg);
320
0
    }
321
0
    return 0;
322
0
  }
323
324
0
  if (!up->rpf.source_nexthop.interface) {
325
0
    if (PIM_DEBUG_PIM_TRACE)
326
0
      zlog_debug("%s: up %s RPF is not present", __func__,
327
0
           up->sg_str);
328
0
    return 0;
329
0
  }
330
331
0
  pim_ifp = up->rpf.source_nexthop.interface->info;
332
333
0
  rpg = pim_ifp ? RP(pim_ifp->pim, sg.grp) : NULL;
334
335
0
  if ((pim_rpf_addr_is_inaddr_any(rpg)) || (!pim_ifp) ||
336
0
      (!(PIM_I_am_DR(pim_ifp)))) {
337
0
    if (PIM_DEBUG_MROUTE) {
338
0
      zlog_debug("%s: Failed Check send packet", __func__);
339
0
    }
340
0
    return 0;
341
0
  }
342
343
  /*
344
   * If we've received a register suppress
345
   */
346
0
  if (!up->t_rs_timer) {
347
0
    if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
348
0
      if (PIM_DEBUG_PIM_REG)
349
0
        zlog_debug(
350
0
          "%pSG register forward skipped as group is SSM",
351
0
          &sg);
352
0
      return 0;
353
0
    }
354
355
0
    if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
356
0
      if (PIM_DEBUG_PIM_REG)
357
0
        zlog_debug(
358
0
          "%s register forward skipped, not FHR",
359
0
          up->sg_str);
360
0
      return 0;
361
0
    }
362
363
0
    pim_register_send((uint8_t *)buf + sizeof(ipv_hdr),
364
0
          len - sizeof(ipv_hdr),
365
0
          pim_ifp->primary_address, rpg, 0, up);
366
0
  }
367
0
  return 0;
368
0
}
369
370
int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, const kernmsg *msg)
371
0
{
372
0
  struct pim_ifchannel *ch;
373
0
  struct pim_interface *pim_ifp;
374
0
  pim_sgaddr sg;
375
376
0
  memset(&sg, 0, sizeof(sg));
377
0
  sg.src = msg->msg_im_src;
378
0
  sg.grp = msg->msg_im_dst;
379
380
  /*
381
    Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
382
383
    RFC 4601 4.8.2.  PIM-SSM-Only Routers
384
385
    iif is the incoming interface of the packet.
386
    if (iif is in inherited_olist(S,G)) {
387
    send Assert(S,G) on iif
388
    }
389
  */
390
391
0
  if (!ifp) {
392
0
    if (PIM_DEBUG_MROUTE)
393
0
      zlog_debug(
394
0
        "%s: WRONGVIF (S,G)=%pSG could not find input interface for input_vif_index=%d",
395
0
        __func__, &sg, msg->msg_im_vif);
396
0
    return -1;
397
0
  }
398
399
0
  pim_ifp = ifp->info;
400
0
  if (!pim_ifp) {
401
0
    if (PIM_DEBUG_MROUTE)
402
0
      zlog_debug(
403
0
        "%s: WRONGVIF (S,G)=%pSG multicast not enabled on interface %s",
404
0
        __func__, &sg, ifp->name);
405
0
    return -2;
406
0
  }
407
408
0
  ch = pim_ifchannel_find(ifp, &sg);
409
0
  if (!ch) {
410
0
    pim_sgaddr star_g = sg;
411
0
    if (PIM_DEBUG_MROUTE)
412
0
      zlog_debug(
413
0
        "%s: WRONGVIF (S,G)=%pSG could not find channel on interface %s",
414
0
        __func__, &sg, ifp->name);
415
416
0
    star_g.src = PIMADDR_ANY;
417
0
    ch = pim_ifchannel_find(ifp, &star_g);
418
0
    if (!ch) {
419
0
      if (PIM_DEBUG_MROUTE)
420
0
        zlog_debug(
421
0
          "%s: WRONGVIF (*,G)=%pSG could not find channel on interface %s",
422
0
          __func__, &star_g, ifp->name);
423
0
      return -3;
424
0
    }
425
0
  }
426
427
  /*
428
    RFC 4601: 4.6.1.  (S,G) Assert Message State Machine
429
430
    Transitions from NoInfo State
431
432
    An (S,G) data packet arrives on interface I, AND
433
    CouldAssert(S,G,I)==TRUE An (S,G) data packet arrived on an
434
    downstream interface that is in our (S,G) outgoing interface
435
    list.  We optimistically assume that we will be the assert
436
    winner for this (S,G), and so we transition to the "I am Assert
437
    Winner" state and perform Actions A1 (below), which will
438
    initiate the assert negotiation for (S,G).
439
  */
440
441
0
  if (ch->ifassert_state != PIM_IFASSERT_NOINFO) {
442
0
    if (PIM_DEBUG_MROUTE) {
443
0
      zlog_debug(
444
0
        "%s: WRONGVIF (S,G)=%s channel is not on Assert NoInfo state for interface %s",
445
0
        __func__, ch->sg_str, ifp->name);
446
0
    }
447
0
    return -4;
448
0
  }
449
450
0
  if (!PIM_IF_FLAG_TEST_COULD_ASSERT(ch->flags)) {
451
0
    if (PIM_DEBUG_MROUTE) {
452
0
      zlog_debug(
453
0
        "%s: WRONGVIF (S,G)=%s interface %s is not downstream for channel",
454
0
        __func__, ch->sg_str, ifp->name);
455
0
    }
456
0
    return -5;
457
0
  }
458
459
0
  if (assert_action_a1(ch)) {
460
0
    if (PIM_DEBUG_MROUTE) {
461
0
      zlog_debug(
462
0
        "%s: WRONGVIF (S,G)=%s assert_action_a1 failure on interface %s",
463
0
        __func__, ch->sg_str, ifp->name);
464
0
    }
465
0
    return -6;
466
0
  }
467
468
0
  return 0;
469
0
}
470
471
int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf,
472
            size_t len)
473
0
{
474
0
  const ipv_hdr *ip_hdr = (const ipv_hdr *)buf;
475
0
  struct pim_interface *pim_ifp;
476
0
  struct pim_instance *pim;
477
0
  struct pim_ifchannel *ch;
478
0
  struct pim_upstream *up;
479
0
  pim_sgaddr star_g;
480
0
  pim_sgaddr sg;
481
482
0
  pim_ifp = ifp->info;
483
484
0
  memset(&sg, 0, sizeof(sg));
485
0
  sg.src = IPV_SRC(ip_hdr);
486
0
  sg.grp = IPV_DST(ip_hdr);
487
488
0
  ch = pim_ifchannel_find(ifp, &sg);
489
0
  if (ch) {
490
0
    if (PIM_DEBUG_MROUTE)
491
0
      zlog_debug(
492
0
        "WRVIFWHOLE (S,G)=%s found ifchannel on interface %s",
493
0
        ch->sg_str, ifp->name);
494
0
    return -1;
495
0
  }
496
497
0
  star_g = sg;
498
0
  star_g.src = PIMADDR_ANY;
499
500
0
  pim = pim_ifp->pim;
501
  /*
502
   * If the incoming interface is the pimreg, then
503
   * we know the callback is associated with a pim register
504
   * packet and there is nothing to do here as that
505
   * normal pim processing will see the packet and allow
506
   * us to do the right thing.
507
   */
508
0
  if (ifp == pim->regiface) {
509
0
    return 0;
510
0
  }
511
512
0
  up = pim_upstream_find(pim_ifp->pim, &sg);
513
0
  if (up) {
514
0
    struct pim_upstream *parent;
515
0
    struct pim_nexthop source;
516
0
    struct pim_rpf *rpf = RP(pim_ifp->pim, sg.grp);
517
518
    /* No RPF or No RPF interface or No mcast on RPF interface */
519
0
    if (!rpf || !rpf->source_nexthop.interface ||
520
0
        !rpf->source_nexthop.interface->info)
521
0
      return 0;
522
523
    /*
524
     * If we have received a WRVIFWHOLE and are at this
525
     * point, we could be receiving the packet on the *,G
526
     * tree, let's check and if so we can safely drop
527
     * it.
528
     */
529
0
    parent = pim_upstream_find(pim_ifp->pim, &star_g);
530
0
    if (parent && parent->rpf.source_nexthop.interface == ifp)
531
0
      return 0;
532
533
0
    pim_ifp = rpf->source_nexthop.interface->info;
534
535
0
    memset(&source, 0, sizeof(source));
536
    /*
537
     * If we are the fhr that means we are getting a callback during
538
     * the pimreg period, so I believe we can ignore this packet
539
     */
540
0
    if (!PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) {
541
      /*
542
       * No if channel, but upstream we are at the RP.
543
       *
544
       * This could be a anycast RP too and we may
545
       * not have received a register packet from
546
       * the source here at all.  So gracefully
547
       * bow out of doing a nexthop lookup and
548
       * setting the SPTBIT to true
549
       */
550
0
      if (!(pim_addr_is_any(up->upstream_register)) &&
551
0
          pim_nexthop_lookup(pim_ifp->pim, &source,
552
0
                 up->upstream_register, 0)) {
553
0
        pim_register_stop_send(source.interface, &sg,
554
0
                   pim_ifp->primary_address,
555
0
                   up->upstream_register);
556
0
        up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
557
0
      }
558
559
0
      pim_upstream_inherited_olist(pim_ifp->pim, up);
560
0
      if (!up->channel_oil->installed)
561
0
        pim_upstream_mroute_add(up->channel_oil,
562
0
              __func__);
563
0
    } else {
564
0
      if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
565
0
        if (pim_nexthop_lookup(pim_ifp->pim, &source,
566
0
                   up->upstream_register,
567
0
                   0))
568
0
          pim_register_stop_send(
569
0
            source.interface, &sg,
570
0
            pim_ifp->primary_address,
571
0
            up->upstream_register);
572
0
        up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
573
0
      } else {
574
        /*
575
         * At this point pimd is connected to
576
         * the source, it has a parent, we are not
577
         * the RP  and the SPTBIT should be set
578
         * since we know *the* S,G is on the SPT.
579
         * The first time this happens, let's cause
580
         * an immediate join to go out so that
581
         * the RP can trim this guy immediately
582
         * if necessary, instead of waiting
583
         * one join/prune send cycle
584
         */
585
0
        if (up->sptbit != PIM_UPSTREAM_SPTBIT_TRUE &&
586
0
            up->parent &&
587
0
            up->rpf.source_nexthop.interface !=
588
0
              up->parent->rpf.source_nexthop
589
0
                .interface) {
590
0
          up->sptbit = PIM_UPSTREAM_SPTBIT_TRUE;
591
0
          pim_jp_agg_single_upstream_send(
592
0
            &up->parent->rpf, up->parent,
593
0
            true);
594
0
        }
595
0
      }
596
0
      pim_upstream_keep_alive_timer_start(
597
0
        up, pim_ifp->pim->keep_alive_time);
598
0
      pim_upstream_inherited_olist(pim_ifp->pim, up);
599
0
      pim_mroute_msg_wholepkt(fd, ifp, buf, len);
600
0
    }
601
0
    return 0;
602
0
  }
603
604
0
  pim_ifp = ifp->info;
605
0
  if (pim_if_connected_to_source(ifp, sg.src)) {
606
0
    up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
607
0
              PIM_UPSTREAM_FLAG_MASK_FHR, __func__,
608
0
              NULL);
609
0
    if (!up) {
610
0
      if (PIM_DEBUG_MROUTE)
611
0
        zlog_debug(
612
0
          "%pSG: WRONGVIF%s unable to create upstream on interface",
613
0
          &sg, ifp->name);
614
0
      return -2;
615
0
    }
616
0
    PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags);
617
0
    pim_upstream_keep_alive_timer_start(
618
0
      up, pim_ifp->pim->keep_alive_time);
619
0
    up->channel_oil->cc.pktcnt++;
620
0
    pim_register_join(up);
621
0
    pim_upstream_inherited_olist(pim_ifp->pim, up);
622
0
    if (!up->channel_oil->installed)
623
0
      pim_upstream_mroute_add(up->channel_oil, __func__);
624
625
    // Send the packet to the RP
626
0
    pim_mroute_msg_wholepkt(fd, ifp, buf, len);
627
0
  } else {
628
0
    up = pim_upstream_add(pim_ifp->pim, &sg, ifp,
629
0
              PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE,
630
0
              __func__, NULL);
631
0
    if (!up->channel_oil->installed)
632
0
      pim_upstream_mroute_add(up->channel_oil, __func__);
633
0
  }
634
635
0
  return 0;
636
0
}
637
638
#if PIM_IPV == 4
639
static int process_igmp_packet(struct pim_instance *pim, const char *buf,
640
             size_t buf_size, ifindex_t ifindex)
641
0
{
642
0
  struct interface *ifp;
643
0
  struct pim_interface *pim_ifp;
644
0
  struct in_addr ifaddr;
645
0
  struct gm_sock *igmp;
646
0
  const struct prefix *connected_src;
647
0
  const struct ip *ip_hdr = (const struct ip *)buf;
648
649
  /* We have the IP packet but we do not know which interface this
650
   * packet was
651
   * received on. Find the interface that is on the same subnet as
652
   * the source
653
   * of the IP packet.
654
   */
655
0
  ifp = if_lookup_by_index(ifindex, pim->vrf->vrf_id);
656
657
0
  if (!ifp || !ifp->info)
658
0
    return 0;
659
660
0
  connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src);
661
662
0
  if (!connected_src && !pim_addr_is_any(ip_hdr->ip_src)) {
663
0
    if (PIM_DEBUG_GM_PACKETS) {
664
0
      zlog_debug(
665
0
        "Recv IGMP packet on interface: %s from a non-connected source: %pI4",
666
0
        ifp->name, &ip_hdr->ip_src);
667
0
    }
668
0
    return 0;
669
0
  }
670
671
0
  pim_ifp = ifp->info;
672
0
  ifaddr = connected_src ? connected_src->u.prefix4
673
0
             : pim_ifp->primary_address;
674
0
  igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
675
676
0
  if (PIM_DEBUG_GM_PACKETS) {
677
0
    zlog_debug(
678
0
      "%s(%s): igmp kernel upcall on %s(%p) for %pI4 -> %pI4",
679
0
      __func__, pim->vrf->name, ifp->name, igmp,
680
0
      &ip_hdr->ip_src, &ip_hdr->ip_dst);
681
0
  }
682
0
  if (igmp)
683
0
    pim_igmp_packet(igmp, (char *)buf, buf_size);
684
0
  else if (PIM_DEBUG_GM_PACKETS)
685
0
    zlog_debug(
686
0
      "No IGMP socket on interface: %s with connected source: %pI4",
687
0
      ifp->name, &ifaddr);
688
689
0
  return 0;
690
0
}
691
#endif
692
693
int pim_mroute_msg(struct pim_instance *pim, const char *buf, size_t buf_size,
694
       ifindex_t ifindex)
695
0
{
696
0
  struct interface *ifp;
697
0
  const ipv_hdr *ip_hdr;
698
0
  const kernmsg *msg;
699
700
0
  if (buf_size < (int)sizeof(ipv_hdr))
701
0
    return 0;
702
703
0
  ip_hdr = (const ipv_hdr *)buf;
704
705
0
#if PIM_IPV == 4
706
0
  if (ip_hdr->ip_p == IPPROTO_IGMP) {
707
0
    process_igmp_packet(pim, buf, buf_size, ifindex);
708
0
  } else if (ip_hdr->ip_p) {
709
0
    if (PIM_DEBUG_MROUTE_DETAIL) {
710
0
      zlog_debug(
711
0
        "%s: no kernel upcall proto=%d src: %pI4 dst: %pI4 msg_size=%ld",
712
0
        __func__, ip_hdr->ip_p, &ip_hdr->ip_src,
713
0
        &ip_hdr->ip_dst, (long int)buf_size);
714
0
    }
715
716
0
  } else {
717
#else
718
719
  if ((ip_hdr->ip6_vfc & 0xf) == 0) {
720
#endif
721
0
    msg = (const kernmsg *)buf;
722
723
0
    ifp = pim_if_find_by_vif_index(pim, msg->msg_im_vif);
724
725
0
    if (!ifp)
726
0
      return 0;
727
0
    if (PIM_DEBUG_MROUTE) {
728
0
#if PIM_IPV == 4
729
0
      zlog_debug(
730
0
        "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI4,%pI4) on %s vifi=%d  size=%ld",
731
0
        __func__, gmmsgtype2str[msg->msg_im_msgtype],
732
0
        msg->msg_im_msgtype, ip_hdr->ip_p,
733
0
        pim->mroute_socket, &msg->msg_im_src,
734
0
        &msg->msg_im_dst, ifp->name, msg->msg_im_vif,
735
0
        (long int)buf_size);
736
#else
737
      zlog_debug(
738
        "%s: pim kernel upcall %s type=%d ip_p=%d from fd=%d for (S,G)=(%pI6,%pI6) on %s vifi=%d  size=%ld",
739
        __func__, gmmsgtype2str[msg->msg_im_msgtype],
740
        msg->msg_im_msgtype, ip_hdr->ip6_nxt,
741
        pim->mroute_socket, &msg->msg_im_src,
742
        &msg->msg_im_dst, ifp->name, msg->msg_im_vif,
743
        (long int)buf_size);
744
#endif
745
0
    }
746
747
0
    switch (msg->msg_im_msgtype) {
748
0
    case GMMSG_WRONGVIF:
749
0
      return pim_mroute_msg_wrongvif(pim->mroute_socket, ifp,
750
0
                   msg);
751
0
    case GMMSG_NOCACHE:
752
0
      return pim_mroute_msg_nocache(pim->mroute_socket, ifp,
753
0
                  msg);
754
0
    case GMMSG_WHOLEPKT:
755
0
      return pim_mroute_msg_wholepkt(pim->mroute_socket, ifp,
756
0
                   (const char *)msg,
757
0
                   buf_size);
758
0
    case GMMSG_WRVIFWHOLE:
759
0
      return pim_mroute_msg_wrvifwhole(pim->mroute_socket,
760
0
               ifp, (const char *)msg,
761
0
               buf_size);
762
0
    default:
763
0
      break;
764
0
    }
765
0
  }
766
767
0
  return 0;
768
0
}
769
770
static void mroute_read(struct event *t)
771
0
{
772
0
  struct pim_instance *pim;
773
0
  static long long count;
774
0
  char buf[10000];
775
0
  int cont = 1;
776
0
  int rd;
777
0
  ifindex_t ifindex;
778
0
  pim = EVENT_ARG(t);
779
0
780
0
  while (cont) {
781
0
    rd = pim_socket_recvfromto(pim->mroute_socket, (uint8_t *)buf,
782
0
             sizeof(buf), NULL, NULL, NULL, NULL,
783
0
             &ifindex);
784
0
    if (rd <= 0) {
785
0
      if (errno == EINTR)
786
0
        continue;
787
0
      if (errno == EWOULDBLOCK || errno == EAGAIN)
788
0
        break;
789
0
790
0
      zlog_warn(
791
0
        "%s: failure reading rd=%d: fd=%d: errno=%d: %s",
792
0
        __func__, rd, pim->mroute_socket, errno,
793
0
        safe_strerror(errno));
794
0
      goto done;
795
0
    }
796
0
797
0
    pim_mroute_msg(pim, buf, rd, ifindex);
798
0
799
0
    count++;
800
0
    if (count % router->packet_process == 0)
801
0
      cont = 0;
802
0
  }
803
0
/* Keep reading */
804
0
done:
805
0
  mroute_read_on(pim);
806
0
807
0
  return;
808
0
}
809
810
static void mroute_read_on(struct pim_instance *pim)
811
0
{
812
0
  event_add_read(router->master, mroute_read, pim, pim->mroute_socket,
813
0
           &pim->thread);
814
0
}
815
816
static void mroute_read_off(struct pim_instance *pim)
817
0
{
818
0
  EVENT_OFF(pim->thread);
819
0
}
820
821
int pim_mroute_socket_enable(struct pim_instance *pim)
822
1
{
823
1
  int fd;
824
825
1
  frr_with_privs(&pimd_privs) {
826
827
#ifndef FUZZING
828
#if PIM_IPV == 4
829
    fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
830
#else
831
    fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
832
#endif
833
    if (fd < 0) {
834
      zlog_warn("Could not create mroute socket: errno=%d: %s",
835
          errno,
836
          safe_strerror(errno));
837
      return -2;
838
    }
839
#else
840
1
    fd = 69;
841
1
#endif
842
843
#ifndef FUZZING
844
#if PIM_IPV == 6
845
    struct icmp6_filter filter[1];
846
    int ret;
847
848
    /* Unlike IPv4, this socket is not used for MLD, so just drop
849
     * everything with an empty ICMP6 filter.  Otherwise we get
850
     * all kinds of garbage here, possibly even non-multicast
851
     * related ICMPv6 traffic (e.g. ping)
852
     *
853
     * (mroute kernel upcall "packets" are injected directly on the
854
     * socket, this sockopt -or any other- has no effect on them)
855
     */
856
    ICMP6_FILTER_SETBLOCKALL(filter);
857
    ret = setsockopt(fd, SOL_ICMPV6, ICMP6_FILTER, filter,
858
         sizeof(filter));
859
    if (ret)
860
      zlog_err(
861
        "(VRF %s) failed to set mroute control filter: %m",
862
        pim->vrf->name);
863
#endif
864
#else
865
1
    fd = 69;
866
1
#endif
867
868
1
#ifdef SO_BINDTODEVICE
869
1
    if (pim->vrf->vrf_id != VRF_DEFAULT
870
0
        && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
871
0
          pim->vrf->name, strlen(pim->vrf->name))) {
872
0
      zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
873
0
          safe_strerror(errno));
874
0
      close(fd);
875
0
      return -3;
876
0
    }
877
1
#endif
878
879
1
  }
880
881
1
  pim->mroute_socket = fd;
882
#ifndef FUZZING
883
  if (pim_mroute_set(pim, 1)) {
884
    zlog_warn(
885
      "Could not enable mroute on socket fd=%d: errno=%d: %s",
886
      fd, errno, safe_strerror(errno));
887
    close(fd);
888
    pim->mroute_socket = -1;
889
    return -3;
890
  }
891
892
  pim->mroute_socket_creation = pim_time_monotonic_sec();
893
894
  mroute_read_on(pim);
895
#endif
896
897
1
  return 0;
898
1
}
899
900
int pim_mroute_socket_disable(struct pim_instance *pim)
901
0
{
902
0
  if (pim_mroute_set(pim, 0)) {
903
0
    zlog_warn(
904
0
      "Could not disable mroute on socket fd=%d: errno=%d: %s",
905
0
      pim->mroute_socket, errno, safe_strerror(errno));
906
0
    return -2;
907
0
  }
908
909
0
  if (close(pim->mroute_socket)) {
910
0
    zlog_warn("Failure closing mroute socket: fd=%d errno=%d: %s",
911
0
        pim->mroute_socket, errno, safe_strerror(errno));
912
0
    return -3;
913
0
  }
914
915
0
  mroute_read_off(pim);
916
0
  pim->mroute_socket = -1;
917
918
0
  return 0;
919
0
}
920
921
/*
922
  For each network interface (e.g., physical or a virtual tunnel) that
923
  would be used for multicast forwarding, a corresponding multicast
924
  interface must be added to the kernel.
925
 */
926
int pim_mroute_add_vif(struct interface *ifp, pim_addr ifaddr,
927
           unsigned char flags)
928
2
{
929
2
  struct pim_interface *pim_ifp = ifp->info;
930
2
  pim_vifctl vc;
931
2
  int err;
932
933
2
  if (PIM_DEBUG_MROUTE)
934
0
    zlog_debug("%s: Add Vif %d (%s[%s])", __func__,
935
2
         pim_ifp->mroute_vif_index, ifp->name,
936
2
         pim_ifp->pim->vrf->name);
937
938
2
  memset(&vc, 0, sizeof(vc));
939
2
  vc.vc_vifi = pim_ifp->mroute_vif_index;
940
2
#if PIM_IPV == 4
941
2
#ifdef VIFF_USE_IFINDEX
942
2
  vc.vc_lcl_ifindex = ifp->ifindex;
943
#else
944
  if (ifaddr.s_addr == INADDR_ANY) {
945
    zlog_warn(
946
      "%s: unnumbered interfaces are not supported on this platform",
947
      __func__);
948
    return -1;
949
  }
950
  memcpy(&vc.vc_lcl_addr, &ifaddr, sizeof(vc.vc_lcl_addr));
951
#endif
952
#else
953
  vc.vc_pifi = ifp->ifindex;
954
#endif
955
2
  vc.vc_flags = flags;
956
2
  vc.vc_threshold = PIM_MROUTE_MIN_TTL;
957
2
  vc.vc_rate_limit = 0;
958
959
2
#if PIM_IPV == 4
960
#ifdef PIM_DVMRP_TUNNEL
961
  if (vc.vc_flags & VIFF_TUNNEL) {
962
    memcpy(&vc.vc_rmt_addr, &vif_remote_addr,
963
           sizeof(vc.vc_rmt_addr));
964
  }
965
#endif
966
2
#endif
967
968
#ifndef FUZZING
969
  err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_ADD_VIF,
970
       (void *)&vc, sizeof(vc));
971
#else
972
2
  err = 0;
973
2
#endif
974
975
2
  if (err) {
976
0
    zlog_warn(
977
0
      "%s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_VIF,vif_index=%d,ifaddr=%pPAs,flag=%d): errno=%d: %s",
978
0
      __func__, pim_ifp->pim->mroute_socket, ifp->ifindex,
979
0
      &ifaddr, flags, errno, safe_strerror(errno));
980
0
    return -2;
981
0
  }
982
983
2
  return 0;
984
2
}
985
986
int pim_mroute_del_vif(struct interface *ifp)
987
0
{
988
0
  struct pim_interface *pim_ifp = ifp->info;
989
0
  pim_vifctl vc;
990
0
  int err;
991
992
0
  if (PIM_DEBUG_MROUTE)
993
0
    zlog_debug("%s: Del Vif %d (%s[%s])", __func__,
994
0
         pim_ifp->mroute_vif_index, ifp->name,
995
0
         pim_ifp->pim->vrf->name);
996
997
0
  memset(&vc, 0, sizeof(vc));
998
0
  vc.vc_vifi = pim_ifp->mroute_vif_index;
999
1000
0
  err = setsockopt(pim_ifp->pim->mroute_socket, PIM_IPPROTO, MRT_DEL_VIF,
1001
0
       (void *)&vc, sizeof(vc));
1002
0
  if (err) {
1003
0
    zlog_warn(
1004
0
      "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_VIF,vif_index=%d): errno=%d: %s",
1005
0
      __FILE__, __func__, pim_ifp->pim->mroute_socket,
1006
0
      pim_ifp->mroute_vif_index, errno, safe_strerror(errno));
1007
0
    return -2;
1008
0
  }
1009
1010
0
  return 0;
1011
0
}
1012
1013
/*
1014
 * Prevent creating MFC entry with OIF=IIF.
1015
 *
1016
 * This is a protection against implementation mistakes.
1017
 *
1018
 * PIM protocol implicitely ensures loopfree multicast topology.
1019
 *
1020
 * IGMP must be protected against adding looped MFC entries created
1021
 * by both source and receiver attached to the same interface. See
1022
 * TODO T22.
1023
 * We shall allow igmp to create upstream when it is DR for the intf.
1024
 * Assume RP reachable via non DR.
1025
 */
1026
bool pim_mroute_allow_iif_in_oil(struct channel_oil *c_oil,
1027
    int oif_index)
1028
0
{
1029
0
#ifdef PIM_ENFORCE_LOOPFREE_MFC
1030
0
  struct interface *ifp_out;
1031
0
  struct pim_interface *pim_ifp;
1032
1033
0
  if (c_oil->up &&
1034
0
    PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(c_oil->up->flags))
1035
0
    return true;
1036
1037
0
  ifp_out = pim_if_find_by_vif_index(c_oil->pim, oif_index);
1038
0
  if (!ifp_out)
1039
0
    return false;
1040
0
  pim_ifp = ifp_out->info;
1041
0
  if (!pim_ifp)
1042
0
    return false;
1043
0
  if ((c_oil->oif_flags[oif_index] & PIM_OIF_FLAG_PROTO_GM) &&
1044
0
      PIM_I_am_DR(pim_ifp))
1045
0
    return true;
1046
1047
0
  return false;
1048
#else
1049
  return true;
1050
#endif
1051
0
}
1052
1053
static inline void pim_mroute_copy(struct channel_oil *out,
1054
           struct channel_oil *in)
1055
0
{
1056
0
  int i;
1057
1058
0
  *oil_origin(out) = *oil_origin(in);
1059
0
  *oil_mcastgrp(out) = *oil_mcastgrp(in);
1060
0
  *oil_parent(out) = *oil_parent(in);
1061
1062
0
  for (i = 0; i < MAXVIFS; ++i) {
1063
0
    if (*oil_parent(out) == i &&
1064
0
        !pim_mroute_allow_iif_in_oil(in, i)) {
1065
0
      oil_if_set(out, i, 0);
1066
0
      continue;
1067
0
    }
1068
1069
0
    if (in->oif_flags[i] & PIM_OIF_FLAG_MUTE)
1070
0
      oil_if_set(out, i, 0);
1071
0
    else
1072
0
      oil_if_set(out, i, oil_if_has(in, i));
1073
0
  }
1074
0
}
1075
1076
/* This function must not be called directly 0
1077
 * use pim_upstream_mroute_add or pim_static_mroute_add instead
1078
 */
1079
static int pim_mroute_add(struct channel_oil *c_oil, const char *name)
1080
0
{
1081
0
  struct pim_instance *pim = c_oil->pim;
1082
0
  struct channel_oil tmp_oil[1] = { };
1083
0
  int err;
1084
1085
0
  pim->mroute_add_last = pim_time_monotonic_sec();
1086
0
  ++pim->mroute_add_events;
1087
1088
  /* Copy the oil to a temporary structure to fixup (without need to
1089
   * later restore) before sending the mroute add to the dataplane
1090
   */
1091
0
  pim_mroute_copy(tmp_oil, c_oil);
1092
1093
  /* The linux kernel *expects* the incoming
1094
   * vif to be part of the outgoing list
1095
   * in the case of a (*,G).
1096
   */
1097
0
  if (pim_addr_is_any(*oil_origin(c_oil))) {
1098
0
    oil_if_set(tmp_oil, *oil_parent(c_oil), 1);
1099
0
  }
1100
1101
  /*
1102
   * If we have an unresolved cache entry for the S,G
1103
   * it is owned by the pimreg for the incoming IIF
1104
   * So set pimreg as the IIF temporarily to cause
1105
   * the packets to be forwarded.  Then set it
1106
   * to the correct IIF afterwords.
1107
   */
1108
0
  if (!c_oil->installed && !pim_addr_is_any(*oil_origin(c_oil))
1109
0
      && *oil_parent(c_oil) != 0) {
1110
0
    *oil_parent(tmp_oil) = 0;
1111
0
  }
1112
  /* For IPv6 MRT_ADD_MFC is defined to MRT6_ADD_MFC */
1113
0
  err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
1114
0
       &tmp_oil->oil, sizeof(tmp_oil->oil));
1115
1116
0
  if (!err && !c_oil->installed
1117
0
      && !pim_addr_is_any(*oil_origin(c_oil))
1118
0
      && *oil_parent(c_oil) != 0) {
1119
0
    *oil_parent(tmp_oil) = *oil_parent(c_oil);
1120
0
    err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_ADD_MFC,
1121
0
         &tmp_oil->oil, sizeof(tmp_oil->oil));
1122
0
  }
1123
1124
0
  if (err) {
1125
0
    zlog_warn(
1126
0
      "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_ADD_MFC): errno=%d: %s",
1127
0
      __FILE__, __func__, pim->mroute_socket, errno,
1128
0
      safe_strerror(errno));
1129
0
    return -2;
1130
0
  }
1131
1132
0
  if (PIM_DEBUG_MROUTE) {
1133
0
    char buf[1000];
1134
0
    zlog_debug("%s(%s), vrf %s Added Route: %s", __func__, name,
1135
0
         pim->vrf->name,
1136
0
         pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1137
0
  }
1138
1139
0
  if (!c_oil->installed) {
1140
0
    c_oil->installed = 1;
1141
0
    c_oil->mroute_creation = pim_time_monotonic_sec();
1142
0
  }
1143
1144
0
  return 0;
1145
0
}
1146
1147
static int pim_upstream_get_mroute_iif(struct channel_oil *c_oil,
1148
    const char *name)
1149
8.99k
{
1150
8.99k
  vifi_t iif = MAXVIFS;
1151
8.99k
  struct interface *ifp = NULL;
1152
8.99k
  struct pim_interface *pim_ifp;
1153
8.99k
  struct pim_upstream *up = c_oil->up;
1154
1155
8.99k
  if (up) {
1156
8.99k
    if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(up->flags)) {
1157
6.73k
      if (up->parent)
1158
3.72k
        ifp = up->parent->rpf.source_nexthop.interface;
1159
6.73k
    } else {
1160
2.25k
      ifp = up->rpf.source_nexthop.interface;
1161
2.25k
    }
1162
8.99k
    if (ifp) {
1163
0
      pim_ifp = (struct pim_interface *)ifp->info;
1164
0
      if (pim_ifp)
1165
0
        iif = pim_ifp->mroute_vif_index;
1166
0
    }
1167
8.99k
  }
1168
8.99k
  return iif;
1169
8.99k
}
1170
1171
static int pim_upstream_mroute_update(struct channel_oil *c_oil,
1172
    const char *name)
1173
1.31k
{
1174
1.31k
  char buf[1000];
1175
1176
1.31k
  if (*oil_parent(c_oil) >= MAXVIFS) {
1177
    /* the c_oil cannot be installed as a mroute yet */
1178
1.31k
    if (PIM_DEBUG_MROUTE)
1179
0
      zlog_debug(
1180
1.31k
          "%s(%s) %s mroute not ready to be installed; %s",
1181
1.31k
          __func__, name,
1182
1.31k
          pim_channel_oil_dump(c_oil, buf,
1183
1.31k
            sizeof(buf)),
1184
1.31k
          c_oil->installed ?
1185
1.31k
          "uninstall" : "skip");
1186
    /* if already installed flush it out as we are going to stop
1187
     * updates to it leaving it in a stale state
1188
     */
1189
1.31k
    if (c_oil->installed)
1190
0
      pim_mroute_del(c_oil, name);
1191
    /* return success (skipped) */
1192
1.31k
    return 0;
1193
1.31k
  }
1194
1195
0
  return pim_mroute_add(c_oil, name);
1196
1.31k
}
1197
1198
/* IIF associated with SGrpt entries are re-evaluated when the parent
1199
 * (*,G) entries IIF changes
1200
 */
1201
static void pim_upstream_all_sources_iif_update(struct pim_upstream *up)
1202
0
{
1203
0
  struct listnode *listnode;
1204
0
  struct pim_upstream *child;
1205
1206
0
  for (ALL_LIST_ELEMENTS_RO(up->sources, listnode,
1207
0
        child)) {
1208
0
    if (PIM_UPSTREAM_FLAG_TEST_USE_RPT(child->flags))
1209
0
      pim_upstream_mroute_iif_update(child->channel_oil,
1210
0
          __func__);
1211
0
  }
1212
0
}
1213
1214
/* In the case of "PIM state machine" added mroutes an upstream entry
1215
 * must be present to decide on the SPT-forwarding vs. RPT-forwarding.
1216
 */
1217
int pim_upstream_mroute_add(struct channel_oil *c_oil, const char *name)
1218
1.31k
{
1219
1.31k
  vifi_t iif;
1220
1221
1.31k
  iif = pim_upstream_get_mroute_iif(c_oil, name);
1222
1223
1.31k
  if (*oil_parent(c_oil) != iif) {
1224
0
    *oil_parent(c_oil) = iif;
1225
0
    if (pim_addr_is_any(*oil_origin(c_oil)) &&
1226
0
        c_oil->up)
1227
0
      pim_upstream_all_sources_iif_update(c_oil->up);
1228
1.31k
  } else {
1229
1.31k
    *oil_parent(c_oil) = iif;
1230
1.31k
  }
1231
1232
1.31k
  return pim_upstream_mroute_update(c_oil, name);
1233
1.31k
}
1234
1235
/* Look for IIF changes and update the dateplane entry only if the IIF
1236
 * has changed.
1237
 */
1238
int pim_upstream_mroute_iif_update(struct channel_oil *c_oil, const char *name)
1239
7.67k
{
1240
7.67k
  vifi_t iif;
1241
7.67k
  char buf[1000];
1242
1243
7.67k
  iif = pim_upstream_get_mroute_iif(c_oil, name);
1244
7.67k
  if (*oil_parent(c_oil) == iif) {
1245
    /* no change */
1246
7.67k
    return 0;
1247
7.67k
  }
1248
0
  *oil_parent(c_oil) = iif;
1249
1250
0
  if (pim_addr_is_any(*oil_origin(c_oil)) &&
1251
0
      c_oil->up)
1252
0
    pim_upstream_all_sources_iif_update(c_oil->up);
1253
1254
0
  if (PIM_DEBUG_MROUTE_DETAIL)
1255
0
    zlog_debug("%s(%s) %s mroute iif update %d",
1256
0
        __func__, name,
1257
0
        pim_channel_oil_dump(c_oil, buf,
1258
0
          sizeof(buf)), iif);
1259
  /* XXX: is this hack needed? */
1260
0
  c_oil->oil_inherited_rescan = 1;
1261
0
  return pim_upstream_mroute_update(c_oil, name);
1262
7.67k
}
1263
1264
int pim_static_mroute_add(struct channel_oil *c_oil, const char *name)
1265
0
{
1266
0
  return pim_mroute_add(c_oil, name);
1267
0
}
1268
1269
void pim_static_mroute_iif_update(struct channel_oil *c_oil,
1270
        int input_vif_index,
1271
        const char *name)
1272
0
{
1273
0
  if (*oil_parent(c_oil) == input_vif_index)
1274
0
    return;
1275
1276
0
  *oil_parent(c_oil) = input_vif_index;
1277
0
  if (input_vif_index == MAXVIFS)
1278
0
    pim_mroute_del(c_oil, name);
1279
0
  else
1280
0
    pim_static_mroute_add(c_oil, name);
1281
0
}
1282
1283
int pim_mroute_del(struct channel_oil *c_oil, const char *name)
1284
84.4k
{
1285
84.4k
  struct pim_instance *pim = c_oil->pim;
1286
84.4k
  int err;
1287
1288
84.4k
  pim->mroute_del_last = pim_time_monotonic_sec();
1289
84.4k
  ++pim->mroute_del_events;
1290
1291
84.4k
  if (!c_oil->installed) {
1292
84.4k
    if (PIM_DEBUG_MROUTE) {
1293
0
      char buf[1000];
1294
0
      zlog_debug(
1295
0
        "%s %s: vifi %d for route is %s not installed, do not need to send del req. ",
1296
0
        __FILE__, __func__, *oil_parent(c_oil),
1297
0
        pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1298
0
    }
1299
84.4k
    return -2;
1300
84.4k
  }
1301
1302
0
  err = setsockopt(pim->mroute_socket, PIM_IPPROTO, MRT_DEL_MFC,
1303
0
       &c_oil->oil, sizeof(c_oil->oil));
1304
0
  if (err) {
1305
0
    if (PIM_DEBUG_MROUTE)
1306
0
      zlog_warn(
1307
0
        "%s %s: failure: setsockopt(fd=%d,PIM_IPPROTO,MRT_DEL_MFC): errno=%d: %s",
1308
0
        __FILE__, __func__, pim->mroute_socket, errno,
1309
0
        safe_strerror(errno));
1310
0
    return -2;
1311
0
  }
1312
1313
0
  if (PIM_DEBUG_MROUTE) {
1314
0
    char buf[1000];
1315
0
    zlog_debug("%s(%s), vrf %s Deleted Route: %s", __func__, name,
1316
0
         pim->vrf->name,
1317
0
         pim_channel_oil_dump(c_oil, buf, sizeof(buf)));
1318
0
  }
1319
1320
  // Reset kernel installed flag
1321
0
  c_oil->installed = 0;
1322
1323
0
  return 0;
1324
0
}
1325
1326
void pim_mroute_update_counters(struct channel_oil *c_oil)
1327
0
{
1328
0
  struct pim_instance *pim = c_oil->pim;
1329
0
  pim_sioc_sg_req sgreq;
1330
1331
0
  c_oil->cc.oldpktcnt = c_oil->cc.pktcnt;
1332
0
  c_oil->cc.oldbytecnt = c_oil->cc.bytecnt;
1333
0
  c_oil->cc.oldwrong_if = c_oil->cc.wrong_if;
1334
1335
0
  if (!c_oil->installed) {
1336
0
    c_oil->cc.lastused = 100 * pim->keep_alive_time;
1337
0
    if (PIM_DEBUG_MROUTE) {
1338
0
      pim_sgaddr sg;
1339
1340
0
      sg.src = *oil_origin(c_oil);
1341
0
      sg.grp = *oil_mcastgrp(c_oil);
1342
0
      zlog_debug("Channel%pSG is not installed no need to collect data from kernel",
1343
0
           &sg);
1344
0
    }
1345
0
    return;
1346
0
  }
1347
1348
1349
0
  memset(&sgreq, 0, sizeof(sgreq));
1350
1351
0
  pim_zlookup_sg_statistics(c_oil);
1352
1353
0
#if PIM_IPV == 4
1354
0
  sgreq.src = *oil_origin(c_oil);
1355
0
  sgreq.grp = *oil_mcastgrp(c_oil);
1356
#else
1357
  sgreq.src = c_oil->oil.mf6cc_origin;
1358
  sgreq.grp = c_oil->oil.mf6cc_mcastgrp;
1359
#endif
1360
0
  if (ioctl(pim->mroute_socket, PIM_SIOCGETSGCNT, &sgreq)) {
1361
0
    pim_sgaddr sg;
1362
1363
0
    sg.src = *oil_origin(c_oil);
1364
0
    sg.grp = *oil_mcastgrp(c_oil);
1365
1366
0
    zlog_warn(
1367
0
      "ioctl(PIM_SIOCGETSGCNT=%lu) failure for (S,G)=%pSG: errno=%d: %s",
1368
0
      (unsigned long)PIM_SIOCGETSGCNT, &sg, errno,
1369
0
      safe_strerror(errno));
1370
0
    return;
1371
0
  }
1372
1373
0
  c_oil->cc.pktcnt = sgreq.pktcnt;
1374
0
  c_oil->cc.bytecnt = sgreq.bytecnt;
1375
0
  c_oil->cc.wrong_if = sgreq.wrong_if;
1376
0
  return;
1377
0
}