Coverage Report

Created: 2026-02-21 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/pimd/pim_ssm.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * IP SSM ranges for FRR
4
 * Copyright (C) 2017 Cumulus Networks, Inc.
5
 */
6
7
#include <zebra.h>
8
9
#include <lib/linklist.h>
10
#include <lib/prefix.h>
11
#include <lib/vty.h>
12
#include <lib/vrf.h>
13
#include <lib/plist.h>
14
#include <lib/lib_errors.h>
15
16
#include "pimd.h"
17
#include "pim_instance.h"
18
#include "pim_ssm.h"
19
#include "pim_igmp.h"
20
21
static void pim_ssm_range_reevaluate(struct pim_instance *pim)
22
0
{
23
0
#if PIM_IPV == 4
24
  /* 1. Setup register state for (S,G) entries if G has changed from SSM
25
   * to
26
   *    ASM.
27
   * 2. check existing (*,G) IGMP registrations to see if they are
28
   * still ASM. if they are now SSM delete them.
29
   * 3. Allow channel setup for IGMP (*,G) members if G is now ASM
30
   * 4. I could tear down all (*,G), (S,G,rpt) states. But that is an
31
   * unnecessary sladge hammer and may not be particularly useful as it is
32
   * likely the SPT switchover has already happened for flows along such
33
   * RPTs.
34
   * As for the RPT states it seems that the best thing to do is let them
35
   * age
36
   * out gracefully. As long as the FHR and LHR do the right thing RPTs
37
   * will
38
   * disappear in time for SSM groups.
39
   */
40
0
  pim_upstream_register_reevaluate(pim);
41
0
  igmp_source_forward_reevaluate_all(pim);
42
0
#endif
43
0
}
44
45
void pim_ssm_prefix_list_update(struct pim_instance *pim,
46
        struct prefix_list *plist)
47
0
{
48
0
  struct pim_ssm *ssm = pim->ssm_info;
49
50
0
  if (!ssm->plist_name
51
0
      || strcmp(ssm->plist_name, prefix_list_name(plist))) {
52
    /* not ours */
53
0
    return;
54
0
  }
55
56
0
  pim_ssm_range_reevaluate(pim);
57
0
}
58
59
static int pim_is_grp_standard_ssm(struct prefix *group)
60
28
{
61
28
  pim_addr addr = pim_addr_from_prefix(group);
62
63
28
  return pim_addr_ssm(addr);
64
28
}
65
66
int pim_is_grp_ssm(struct pim_instance *pim, pim_addr group_addr)
67
28
{
68
28
  struct pim_ssm *ssm;
69
28
  struct prefix group;
70
28
  struct prefix_list *plist;
71
72
28
  pim_addr_to_prefix(&group, group_addr);
73
74
28
  ssm = pim->ssm_info;
75
28
  if (!ssm->plist_name) {
76
28
    return pim_is_grp_standard_ssm(&group);
77
28
  }
78
79
0
  plist = prefix_list_lookup(PIM_AFI, ssm->plist_name);
80
0
  if (!plist)
81
0
    return 0;
82
83
0
  return (prefix_list_apply_ext(plist, NULL, &group, true) ==
84
0
    PREFIX_PERMIT);
85
0
}
86
87
int pim_ssm_range_set(struct pim_instance *pim, vrf_id_t vrf_id,
88
          const char *plist_name)
89
0
{
90
0
  struct pim_ssm *ssm;
91
0
  int change = 0;
92
93
0
  if (vrf_id != pim->vrf->vrf_id)
94
0
    return PIM_SSM_ERR_NO_VRF;
95
96
0
  ssm = pim->ssm_info;
97
0
  if (plist_name) {
98
0
    if (ssm->plist_name) {
99
0
      if (!strcmp(ssm->plist_name, plist_name))
100
0
        return PIM_SSM_ERR_DUP;
101
0
      XFREE(MTYPE_PIM_FILTER_NAME, ssm->plist_name);
102
0
    }
103
0
    ssm->plist_name = XSTRDUP(MTYPE_PIM_FILTER_NAME, plist_name);
104
0
    change = 1;
105
0
  } else {
106
0
    if (ssm->plist_name) {
107
0
      change = 1;
108
0
      XFREE(MTYPE_PIM_FILTER_NAME, ssm->plist_name);
109
0
    }
110
0
  }
111
112
0
  if (change)
113
0
    pim_ssm_range_reevaluate(pim);
114
115
0
  return PIM_SSM_ERR_NONE;
116
0
}
117
118
void *pim_ssm_init(void)
119
1
{
120
1
  struct pim_ssm *ssm;
121
122
1
  ssm = XCALLOC(MTYPE_PIM_SSM_INFO, sizeof(*ssm));
123
124
1
  return ssm;
125
1
}
126
127
void pim_ssm_terminate(struct pim_ssm *ssm)
128
0
{
129
0
  if (!ssm)
130
0
    return;
131
132
0
  XFREE(MTYPE_PIM_FILTER_NAME, ssm->plist_name);
133
134
  XFREE(MTYPE_PIM_SSM_INFO, ssm);
135
0
}