]>
Commit | Line | Data |
---|---|---|
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 | ||
18 | static struct channel_oil * | |
19 | tib_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 | ||
81 | bool 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 | ||
135 | void 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 | } |