]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_oil.c
pimd: Add debug messages as to why a register packet is rejected.
[mirror_frr.git] / pimd / pim_oil.c
CommitLineData
12e41d03
DL
1/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "log.h"
25#include "memory.h"
26#include "linklist.h"
744d91b3 27#include "if.h"
12e41d03
DL
28
29#include "pimd.h"
30#include "pim_oil.h"
31#include "pim_str.h"
32#include "pim_iface.h"
37653d4f 33#include "pim_time.h"
12e41d03
DL
34
35void pim_channel_oil_free(struct channel_oil *c_oil)
36{
37 XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
38}
39
7293a053
DS
40static void
41pim_del_channel_oil (struct channel_oil *c_oil)
12e41d03
DL
42{
43 /*
44 notice that listnode_delete() can't be moved
45 into pim_channel_oil_free() because the later is
46 called by list_delete_all_node()
47 */
48 listnode_delete(qpim_channel_oil_list, c_oil);
49
50 pim_channel_oil_free(c_oil);
51}
52
7293a053 53static struct channel_oil *
4ed0af70 54pim_add_channel_oil (struct prefix_sg *sg,
7293a053 55 int input_vif_index)
12e41d03
DL
56{
57 struct channel_oil *c_oil;
7293a053 58 struct interface *ifp;
12e41d03 59
7293a053
DS
60 ifp = pim_if_find_by_vif_index(input_vif_index);
61 if (!ifp) {
12e41d03 62 /* warning only */
05e451f8 63 zlog_warn("%s: (S,G)=%s could not find input interface for input_vif_index=%d",
12e41d03 64 __PRETTY_FUNCTION__,
05e451f8 65 pim_str_sg_dump (sg), input_vif_index);
12e41d03
DL
66 }
67
68 c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
69 if (!c_oil) {
70 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
7293a053 71 return NULL;
12e41d03
DL
72 }
73
4ed0af70
DS
74 c_oil->oil.mfcc_mcastgrp = sg->grp;
75 c_oil->oil.mfcc_origin = sg->src;
12e41d03
DL
76 c_oil->oil.mfcc_parent = input_vif_index;
77 c_oil->oil_ref_count = 1;
58302dc7 78 c_oil->installed = 0;
12e41d03 79
12e41d03
DL
80 listnode_add(qpim_channel_oil_list, c_oil);
81
82 return c_oil;
83}
84
4ed0af70 85static struct channel_oil *pim_find_channel_oil(struct prefix_sg *sg)
12e41d03
DL
86{
87 struct listnode *node;
88 struct channel_oil *c_oil;
89
90 for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
4ed0af70
DS
91 if ((sg->grp.s_addr == c_oil->oil.mfcc_mcastgrp.s_addr) &&
92 (sg->src.s_addr == c_oil->oil.mfcc_origin.s_addr))
12e41d03
DL
93 return c_oil;
94 }
95
96 return 0;
97}
98
4ed0af70 99struct channel_oil *pim_channel_oil_add(struct prefix_sg *sg,
12e41d03
DL
100 int input_vif_index)
101{
102 struct channel_oil *c_oil;
103
05e451f8 104 c_oil = pim_find_channel_oil(sg);
12e41d03
DL
105 if (c_oil) {
106 ++c_oil->oil_ref_count;
107 return c_oil;
108 }
109
05e451f8 110 return pim_add_channel_oil(sg, input_vif_index);
12e41d03
DL
111}
112
113void pim_channel_oil_del(struct channel_oil *c_oil)
114{
115 --c_oil->oil_ref_count;
116
117 if (c_oil->oil_ref_count < 1) {
7293a053 118 pim_del_channel_oil(c_oil);
12e41d03
DL
119 }
120}
1865a44a 121
887fa014
DS
122int
123pim_channel_del_oif (struct channel_oil *channel_oil,
124 struct interface *oif,
125 uint32_t proto_mask)
126{
127 struct pim_interface *pim_ifp;
128
129 zassert (channel_oil);
130 zassert (oif);
131
132 pim_ifp = oif->info;
133
134 if (PIM_DEBUG_MROUTE)
135 {
136 char group_str[100];
137 char source_str[100];
138 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
139 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
140 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
141 __FILE__, __PRETTY_FUNCTION__,
142 source_str, group_str,
143 proto_mask, oif->name, pim_ifp->mroute_vif_index);
144 }
145
146 /*
147 * Don't do anything if we've been asked to remove a source
148 * that is not actually on it.
149 */
150 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask))
151 {
152 if (PIM_DEBUG_MROUTE)
153 {
154 char group_str[100];
155 char source_str[100];
156 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
157 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
158 zlog_debug("%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
159 __FILE__, __PRETTY_FUNCTION__,
160 proto_mask, channel_oil->oif_flags[pim_ifp->mroute_vif_index],
161 oif->name, pim_ifp->mroute_vif_index,
162 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
163 source_str, group_str);
164 }
165 return 0;
166 }
167
168 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
169
170 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index])
171 {
172 if (PIM_DEBUG_MROUTE)
173 {
174 char group_str[100];
175 char source_str[100];
176 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
177 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
178 zlog_debug("%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
179 __FILE__, __PRETTY_FUNCTION__,
180 oif->name, pim_ifp->mroute_vif_index,
181 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
182 source_str, group_str);
183 }
184 return 0;
185 }
186
187 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
188
189 if (pim_mroute_add (channel_oil)) {
190 if (PIM_DEBUG_MROUTE)
191 {
192 char group_str[100];
193 char source_str[100];
194 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
195 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
196 zlog_debug("%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
197 __FILE__, __PRETTY_FUNCTION__,
198 oif->name, pim_ifp->mroute_vif_index,
199 source_str, group_str);
200 }
201 return -1;
202 }
203
204 return 0;
205}
206
207
1865a44a
DS
208int pim_channel_add_oif(struct channel_oil *channel_oil,
209 struct interface *oif,
210 uint32_t proto_mask)
211{
212 struct pim_interface *pim_ifp;
213 int old_ttl;
214
75395e6a
DS
215 /*
216 * If we've gotten here we've gone bad, but let's
217 * not take down pim
218 */
219 if (!channel_oil)
220 {
221 zlog_warn ("Attempt to Add OIF for non-existent channel oil");
222 return -1;
223 }
1865a44a
DS
224
225 pim_ifp = oif->info;
226
227 if (PIM_DEBUG_MROUTE) {
228 char group_str[100];
229 char source_str[100];
230 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
231 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
232 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
233 __FILE__, __PRETTY_FUNCTION__,
234 source_str, group_str,
235 proto_mask, oif->name, pim_ifp->mroute_vif_index);
236 }
237
1865a44a
DS
238#ifdef PIM_ENFORCE_LOOPFREE_MFC
239 /*
240 Prevent creating MFC entry with OIF=IIF.
241
242 This is a protection against implementation mistakes.
243
244 PIM protocol implicitely ensures loopfree multicast topology.
245
246 IGMP must be protected against adding looped MFC entries created
247 by both source and receiver attached to the same interface. See
248 TODO T22.
249 */
250 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
e6dad1ab
DS
251 if (PIM_DEBUG_MROUTE)
252 {
253 char group_str[100];
254 char source_str[100];
255 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
256 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
257 zlog_debug("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
258 __FILE__, __PRETTY_FUNCTION__,
259 proto_mask, oif->name, pim_ifp->mroute_vif_index,
260 source_str, group_str);
261 }
1865a44a
DS
262 return -2;
263 }
264#endif
265
1865a44a
DS
266 /* Prevent single protocol from subscribing same interface to
267 channel (S,G) multiple times */
268 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
e6dad1ab
DS
269 if (PIM_DEBUG_MROUTE)
270 {
271 char group_str[100];
272 char source_str[100];
273 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
274 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
275 zlog_debug("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
276 __FILE__, __PRETTY_FUNCTION__,
277 proto_mask, oif->name, pim_ifp->mroute_vif_index,
278 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
279 source_str, group_str);
280 }
1865a44a
DS
281 return -3;
282 }
283
284 /* Allow other protocol to request subscription of same interface to
285 channel (S,G) multiple times, by silently ignoring further
286 requests */
287 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
288
289 /* Check the OIF really exists before returning, and only log
290 warning otherwise */
291 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
e6dad1ab
DS
292 if (PIM_DEBUG_MROUTE)
293 {
294 char group_str[100];
295 char source_str[100];
296 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
297 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
298 zlog_debug("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
299 __FILE__, __PRETTY_FUNCTION__,
300 proto_mask, oif->name, pim_ifp->mroute_vif_index,
301 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
302 source_str, group_str);
303 }
1865a44a
DS
304 }
305
306 return 0;
307 }
308
309 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
310
311 if (old_ttl > 0) {
e6dad1ab
DS
312 if (PIM_DEBUG_MROUTE)
313 {
314 char group_str[100];
315 char source_str[100];
316 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
317 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
318 zlog_debug("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
319 __FILE__, __PRETTY_FUNCTION__,
320 oif->name, pim_ifp->mroute_vif_index,
321 source_str, group_str);
322 }
1865a44a
DS
323 return -4;
324 }
325
326 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
327
c171d6d8 328 if (pim_mroute_add(channel_oil)) {
e6dad1ab
DS
329 if (PIM_DEBUG_MROUTE)
330 {
331 char group_str[100];
332 char source_str[100];
333 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
334 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
335 zlog_debug("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
336 __FILE__, __PRETTY_FUNCTION__,
337 oif->name, pim_ifp->mroute_vif_index,
338 source_str, group_str);
339 }
1865a44a
DS
340
341 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
342 return -5;
343 }
344
345 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
346 ++channel_oil->oil_size;
347 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
348
349 if (PIM_DEBUG_MROUTE) {
350 char group_str[100];
351 char source_str[100];
352 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
353 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
354 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
355 __FILE__, __PRETTY_FUNCTION__,
356 source_str, group_str,
357 proto_mask, oif->name, pim_ifp->mroute_vif_index);
358 }
359
360 return 0;
361}