]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_tib.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / pimd / pim_tib.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: GPL-2.0-or-later
cd6d2858
DL
2/*
3 * TIB (Tree Information Base) - just PIM <> IGMP/MLD glue for now
4 * Copyright (C) 2022 David Lamparter for NetDEF, Inc.
cd6d2858
DL
5 */
6
7#include <zebra.h>
8
9#include "pim_tib.h"
10
11#include "pimd.h"
993e3d8e 12#include "pim_instance.h"
cd6d2858
DL
13#include "pim_iface.h"
14#include "pim_upstream.h"
15#include "pim_oil.h"
16#include "pim_nht.h"
17
18static struct channel_oil *
19tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif)
20{
21 struct pim_interface *pim_oif = oif->info;
22 int input_iface_vif_index = 0;
23 pim_addr vif_source;
6b362f9f 24 struct prefix grp;
cd6d2858
DL
25 struct pim_nexthop nexthop;
26 struct pim_upstream *up = NULL;
27
28 if (!pim_rp_set_upstream_addr(pim, &vif_source, sg.src, sg.grp)) {
29 /* no PIM RP - create a dummy channel oil */
30 return pim_channel_oil_add(pim, &sg, __func__);
31 }
32
cd6d2858
DL
33 pim_addr_to_prefix(&grp, sg.grp);
34
35 up = pim_upstream_find(pim, &sg);
36 if (up) {
37 memcpy(&nexthop, &up->rpf.source_nexthop,
38 sizeof(struct pim_nexthop));
f13530f2
SG
39 (void)pim_ecmp_nexthop_lookup(pim, &nexthop, vif_source, &grp,
40 0);
cd6d2858
DL
41 if (nexthop.interface)
42 input_iface_vif_index = pim_if_find_vifindex_by_ifindex(
43 pim, nexthop.interface->ifindex);
44 } else
e6e53006 45 input_iface_vif_index =
46 pim_ecmp_fib_lookup_if_vif_index(pim, vif_source, &grp);
cd6d2858
DL
47
48 if (PIM_DEBUG_ZEBRA)
49 zlog_debug("%s: NHT %pSG vif_source %pPAs vif_index:%d",
50 __func__, &sg, &vif_source, input_iface_vif_index);
51
52 if (input_iface_vif_index < 1) {
a96d64b0 53 if (PIM_DEBUG_GM_TRACE)
cd6d2858
DL
54 zlog_debug(
55 "%s %s: could not find input interface for %pSG",
56 __FILE__, __func__, &sg);
57
58 return pim_channel_oil_add(pim, &sg, __func__);
59 }
60
61 /*
62 * Protect IGMP against adding looped MFC entries created by both
63 * source and receiver attached to the same interface. See TODO T22.
64 * Block only when the intf is non DR DR must create upstream.
65 */
66 if ((input_iface_vif_index == pim_oif->mroute_vif_index) &&
67 !(PIM_I_am_DR(pim_oif))) {
68 /* ignore request for looped MFC entry */
a96d64b0 69 if (PIM_DEBUG_GM_TRACE)
cd6d2858
DL
70 zlog_debug(
71 "%s: ignoring request for looped MFC entry (S,G)=%pSG: oif=%s vif_index=%d",
72 __func__, &sg, oif->name,
73 input_iface_vif_index);
74
75 return NULL;
76 }
77
78 return pim_channel_oil_add(pim, &sg, __func__);
79}
80
81bool tib_sg_gm_join(struct pim_instance *pim, pim_sgaddr sg,
82 struct interface *oif, struct channel_oil **oilp)
83{
84 struct pim_interface *pim_oif = oif->info;
85
86 if (!pim_oif) {
a96d64b0 87 if (PIM_DEBUG_GM_TRACE)
cd6d2858
DL
88 zlog_debug("%s: multicast not enabled on oif=%s?",
89 __func__, oif->name);
90 return false;
91 }
92
93 if (!*oilp)
94 *oilp = tib_sg_oil_setup(pim, sg, oif);
95 if (!*oilp)
96 return false;
97
98 if (PIM_I_am_DR(pim_oif) || PIM_I_am_DualActive(pim_oif)) {
99 int result;
100
80a82b56
A
101 result = pim_channel_add_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_GM,
102 __func__);
cd6d2858
DL
103 if (result) {
104 if (PIM_DEBUG_MROUTE)
105 zlog_warn("%s: add_oif() failed with return=%d",
106 __func__, result);
107 return false;
108 }
109 } else {
a96d64b0 110 if (PIM_DEBUG_GM_TRACE)
cd6d2858
DL
111 zlog_debug(
112 "%s: %pSG was received on %s interface but we are not DR for that interface",
113 __func__, &sg, oif->name);
114
115 return false;
116 }
117 /*
118 Feed IGMPv3-gathered local membership information into PIM
119 per-interface (S,G) state.
120 */
121 if (!pim_ifchannel_local_membership_add(oif, &sg, false /*is_vxlan*/)) {
122 if (PIM_DEBUG_MROUTE)
123 zlog_warn(
124 "%s: Failure to add local membership for %pSG",
125 __func__, &sg);
126
80a82b56 127 pim_channel_del_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_GM,
cd6d2858
DL
128 __func__);
129 return false;
130 }
131
132 return true;
133}
134
135void tib_sg_gm_prune(struct pim_instance *pim, pim_sgaddr sg,
136 struct interface *oif, struct channel_oil **oilp)
137{
138 int result;
139
140 /*
141 It appears that in certain circumstances that
142 igmp_source_forward_stop is called when IGMP forwarding
143 was not enabled in oif_flags for this outgoing interface.
144 Possibly because of multiple calls. When that happens, we
145 enter the below if statement and this function returns early
146 which in turn triggers the calling function to assert.
147 Making the call to pim_channel_del_oif and ignoring the return code
148 fixes the issue without ill effect, similar to
149 pim_forward_stop below.
150 */
80a82b56 151 result = pim_channel_del_oif(*oilp, oif, PIM_OIF_FLAG_PROTO_GM,
cd6d2858
DL
152 __func__);
153 if (result) {
a96d64b0 154 if (PIM_DEBUG_GM_TRACE)
cd6d2858
DL
155 zlog_debug(
156 "%s: pim_channel_del_oif() failed with return=%d",
157 __func__, result);
158 return;
159 }
160
161 /*
162 Feed IGMPv3-gathered local membership information into PIM
163 per-interface (S,G) state.
164 */
165 pim_ifchannel_local_membership_del(oif, &sg);
166}