]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_oil.c
Merge pull request #10744 from opensourcerouting/igmp-json-leave-typo
[mirror_frr.git] / pimd / pim_oil.c
CommitLineData
12e41d03 1/*
896014f4
DL
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 along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
12e41d03
DL
19
20#include <zebra.h>
21
22#include "log.h"
23#include "memory.h"
24#include "linklist.h"
744d91b3 25#include "if.h"
040d86ad
DS
26#include "hash.h"
27#include "jhash.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"
5923b739 34#include "pim_vxlan.h"
12e41d03 35
a155fed5
AK
36static void pim_channel_update_mute(struct channel_oil *c_oil);
37
d62a17ae 38char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size)
781a1745 39{
a2dc7057 40 char *out;
9bf5f19c 41 struct interface *ifp;
6fff2cc6 42 pim_sgaddr sg;
d62a17ae 43 int i;
44
a9338fa4
DL
45 sg.src = *oil_origin(c_oil);
46 sg.grp = *oil_mcastgrp(c_oil);
47 ifp = pim_if_find_by_vif_index(c_oil->pim, *oil_parent(c_oil));
98a81d2b
DL
48 snprintfrr(buf, size, "%pSG IIF: %s, OIFS: ", &sg,
49 ifp ? ifp->name : "(?)");
d62a17ae 50
a2dc7057 51 out = buf + strlen(buf);
d62a17ae 52 for (i = 0; i < MAXVIFS; i++) {
a9338fa4 53 if (oil_if_has(c_oil, i) != 0) {
9bf5f19c
DS
54 ifp = pim_if_find_by_vif_index(c_oil->pim, i);
55 snprintf(out, buf + size - out, "%s ",
56 ifp ? ifp->name : "(?)");
a2dc7057 57 out += strlen(out);
d62a17ae 58 }
59 }
60
61 return buf;
781a1745
DS
62}
63
a9338fa4
DL
64int pim_channel_oil_compare(const struct channel_oil *cc1,
65 const struct channel_oil *cc2)
040d86ad 66{
a9338fa4
DL
67 struct channel_oil *c1 = (struct channel_oil *)cc1;
68 struct channel_oil *c2 = (struct channel_oil *)cc2;
69 int rv;
70
71 rv = pim_addr_cmp(*oil_mcastgrp(c1), *oil_mcastgrp(c2));
72 if (rv)
73 return rv;
74 rv = pim_addr_cmp(*oil_origin(c1), *oil_origin(c2));
75 if (rv)
76 return rv;
d62a17ae 77 return 0;
040d86ad
DS
78}
79
611925dc 80void pim_oil_init(struct pim_instance *pim)
040d86ad 81{
7315ecda 82 rb_pim_oil_init(&pim->channel_oil_head);
040d86ad
DS
83}
84
611925dc 85void pim_oil_terminate(struct pim_instance *pim)
040d86ad 86{
7315ecda
DS
87 struct channel_oil *c_oil;
88
89 while ((c_oil = rb_pim_oil_pop(&pim->channel_oil_head)))
90 pim_channel_oil_free(c_oil);
040d86ad 91
7315ecda 92 rb_pim_oil_fini(&pim->channel_oil_head);
040d86ad
DS
93}
94
12e41d03
DL
95void pim_channel_oil_free(struct channel_oil *c_oil)
96{
d62a17ae 97 XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
12e41d03
DL
98}
99
4d9ad5dc 100struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
6fff2cc6 101 pim_sgaddr *sg)
12e41d03 102{
d62a17ae 103 struct channel_oil *c_oil = NULL;
104 struct channel_oil lookup;
d270b216 105
a9338fa4
DL
106 *oil_mcastgrp(&lookup) = sg->grp;
107 *oil_origin(&lookup) = sg->src;
d270b216 108
7315ecda 109 c_oil = rb_pim_oil_find(&pim->channel_oil_head, &lookup);
d270b216 110
d62a17ae 111 return c_oil;
12e41d03
DL
112}
113
611925dc 114struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
6fff2cc6 115 pim_sgaddr *sg, const char *name)
12e41d03 116{
d62a17ae 117 struct channel_oil *c_oil;
d62a17ae 118
611925dc 119 c_oil = pim_find_channel_oil(pim, sg);
d62a17ae 120 if (c_oil) {
d62a17ae 121 ++c_oil->oil_ref_count;
a155fed5
AK
122
123 if (!c_oil->up) {
124 /* channel might be present prior to upstream */
125 c_oil->up = pim_upstream_find(
126 pim, sg);
127 /* if the upstream entry is being anchored to an
128 * already existing channel OIL we need to re-evaluate
129 * the "Mute" state on AA OIFs
130 */
131 pim_channel_update_mute(c_oil);
132 }
8a3e7e9e 133
7984af18
AK
134 /* check if the IIF has changed
135 * XXX - is this really needed
136 */
137 pim_upstream_mroute_iif_update(c_oil, __func__);
138
8a3e7e9e
DS
139 if (PIM_DEBUG_MROUTE)
140 zlog_debug(
6fff2cc6 141 "%s(%s): Existing oil for %pSG Ref Count: %d (Post Increment)",
15569c58 142 __func__, name, sg, c_oil->oil_ref_count);
d62a17ae 143 return c_oil;
144 }
145
d62a17ae 146 c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
d62a17ae 147
a9338fa4
DL
148 *oil_mcastgrp(c_oil) = sg->grp;
149 *oil_origin(c_oil) = sg->src;
d62a17ae 150
a9338fa4 151 *oil_parent(c_oil) = MAXVIFS;
d62a17ae 152 c_oil->oil_ref_count = 1;
153 c_oil->installed = 0;
611925dc
DS
154 c_oil->up = pim_upstream_find(pim, sg);
155 c_oil->pim = pim;
d62a17ae 156
7315ecda 157 rb_pim_oil_add(&pim->channel_oil_head, c_oil);
d62a17ae 158
8a3e7e9e 159 if (PIM_DEBUG_MROUTE)
98a81d2b 160 zlog_debug("%s(%s): c_oil %pSG add", __func__, name, sg);
7984af18 161
d62a17ae 162 return c_oil;
12e41d03
DL
163}
164
a155fed5 165struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil,
17823cdd 166 const char *name)
12e41d03 167{
8a3e7e9e 168 if (PIM_DEBUG_MROUTE) {
a9338fa4
DL
169 pim_sgaddr sg = {.src = *oil_mcastgrp(c_oil),
170 .grp = *oil_origin(c_oil)};
8a3e7e9e
DS
171
172 zlog_debug(
6fff2cc6 173 "%s(%s): Del oil for %pSG, Ref Count: %d (Predecrement)",
15569c58 174 __func__, name, &sg, c_oil->oil_ref_count);
8a3e7e9e 175 }
d62a17ae 176 --c_oil->oil_ref_count;
177
178 if (c_oil->oil_ref_count < 1) {
179 /*
180 * notice that listnode_delete() can't be moved
181 * into pim_channel_oil_free() because the later is
182 * called by list_delete_all_node()
183 */
184 c_oil->up = NULL;
7315ecda 185 rb_pim_oil_del(&c_oil->pim->channel_oil_head, c_oil);
d62a17ae 186
187 pim_channel_oil_free(c_oil);
a155fed5
AK
188 return NULL;
189 }
190
191 return c_oil;
192}
193
194void pim_channel_oil_upstream_deref(struct channel_oil *c_oil)
195{
196 /* The upstream entry associated with a channel_oil is abt to be
197 * deleted. If the channel_oil is kept around because of other
198 * references we need to remove upstream based states out of it.
199 */
200 c_oil = pim_channel_oil_del(c_oil, __func__);
201 if (c_oil) {
202 /* note: here we assume that c_oil->up has already been
203 * cleared
204 */
205 pim_channel_update_mute(c_oil);
d62a17ae 206 }
12e41d03 207}
1865a44a 208
d62a17ae 209int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
1b249e70 210 uint32_t proto_mask, const char *caller)
887fa014 211{
d62a17ae 212 struct pim_interface *pim_ifp;
213
df5dfb77
DL
214 assert(channel_oil);
215 assert(oif);
d62a17ae 216
217 pim_ifp = oif->info;
218
219 /*
220 * Don't do anything if we've been asked to remove a source
221 * that is not actually on it.
222 */
223 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
224 if (PIM_DEBUG_MROUTE) {
d62a17ae 225 zlog_debug(
a9338fa4 226 "%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
15569c58 227 __FILE__, __func__, proto_mask,
d62a17ae 228 channel_oil
229 ->oif_flags[pim_ifp->mroute_vif_index],
230 oif->name, pim_ifp->mroute_vif_index,
a9338fa4
DL
231 oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
232 oil_origin(channel_oil),
233 oil_mcastgrp(channel_oil));
d62a17ae 234 }
235 return 0;
236 }
237
238 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
239
5923b739
AK
240 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] &
241 PIM_OIF_FLAG_PROTO_ANY) {
d62a17ae 242 if (PIM_DEBUG_MROUTE) {
d62a17ae 243 zlog_debug(
a9338fa4 244 "%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
15569c58 245 __FILE__, __func__, oif->name,
d62a17ae 246 pim_ifp->mroute_vif_index,
a9338fa4
DL
247 oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
248 oil_origin(channel_oil),
249 oil_mcastgrp(channel_oil));
d62a17ae 250 }
251 return 0;
252 }
253
a9338fa4 254 oil_if_set(channel_oil, pim_ifp->mroute_vif_index, false);
5923b739
AK
255 /* clear mute; will be re-evaluated when the OIF becomes valid again */
256 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~PIM_OIF_FLAG_MUTE;
d62a17ae 257
15569c58 258 if (pim_upstream_mroute_add(channel_oil, __func__)) {
d62a17ae 259 if (PIM_DEBUG_MROUTE) {
d62a17ae 260 zlog_debug(
a9338fa4 261 "%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%pPAs,%pPAs)",
15569c58 262 __FILE__, __func__, oif->name,
a9338fa4
DL
263 pim_ifp->mroute_vif_index,
264 oil_origin(channel_oil),
265 oil_mcastgrp(channel_oil));
d62a17ae 266 }
267 return -1;
887fa014 268 }
d62a17ae 269
270 --channel_oil->oil_size;
271
272 if (PIM_DEBUG_MROUTE) {
d62a17ae 273 zlog_debug(
a9338fa4
DL
274 "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
275 __func__, caller, oil_origin(channel_oil),
276 oil_mcastgrp(channel_oil),
277 proto_mask,
278 *oil_parent(channel_oil), oif->name,
d62a17ae 279 pim_ifp->mroute_vif_index);
887fa014 280 }
d62a17ae 281
282 return 0;
887fa014
DS
283}
284
1537a668
AK
285void pim_channel_del_inherited_oif(struct channel_oil *c_oil,
286 struct interface *oif, const char *caller)
287{
288 struct pim_upstream *up = c_oil->up;
289
290 pim_channel_del_oif(c_oil, oif, PIM_OIF_FLAG_PROTO_STAR,
291 caller);
292
293 /* if an inherited OIF is being removed join-desired can change
294 * if the inherited OIL is now empty and KAT is running
295 */
2a27f13b
DL
296 if (up && !pim_addr_is_any(up->sg.src) &&
297 pim_upstream_empty_inherited_olist(up))
1537a668
AK
298 pim_upstream_update_join_desired(up->pim, up);
299}
887fa014 300
5923b739
AK
301static bool pim_channel_eval_oif_mute(struct channel_oil *c_oil,
302 struct pim_interface *pim_ifp)
303{
304 struct pim_interface *pim_reg_ifp;
305 struct pim_interface *vxlan_ifp;
306 bool do_mute = false;
307 struct pim_instance *pim = c_oil->pim;
308
309 if (!c_oil->up)
310 return do_mute;
311
312 pim_reg_ifp = pim->regiface->info;
313 if (pim_ifp == pim_reg_ifp) {
314 /* suppress pimreg in the OIL if the mroute is not supposed to
315 * trigger register encapsulated data
316 */
317 if (PIM_UPSTREAM_FLAG_TEST_NO_PIMREG_DATA(c_oil->up->flags))
318 do_mute = true;
319
320 return do_mute;
321 }
322
323 vxlan_ifp = pim_vxlan_get_term_ifp(pim);
324 if (pim_ifp == vxlan_ifp) {
325 /* 1. vxlan termination device must never be added to the
326 * origination mroute (and that can actually happen because
327 * of XG inheritance from the termination mroute) otherwise
328 * traffic will end up looping.
329 * PS: This check has also been extended to non-orig mroutes
330 * that have a local SIP as such mroutes can move back and
331 * forth between orig<=>non-orig type.
332 * 2. vxlan termination device should be removed from the non-DF
333 * to prevent duplicates to the overlay rxer
334 */
335 if (PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(c_oil->up->flags) ||
336 PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags) ||
337 pim_vxlan_is_local_sip(c_oil->up))
338 do_mute = true;
339
340 return do_mute;
341 }
342
df94b33a
DS
343 if (PIM_I_am_DualActive(pim_ifp)) {
344 struct pim_upstream *starup = c_oil->up->parent;
345 if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(c_oil->up->flags)
346 && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(c_oil->up->flags)))
347 do_mute = true;
348
349 /* In case entry is (S,G), Negotiation happens at (*.G) */
350 if (starup
351
352 && PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(starup->flags)
353 && (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(starup->flags)))
354 do_mute = true;
355 return do_mute;
356 }
5923b739
AK
357 return do_mute;
358}
359
360void pim_channel_update_oif_mute(struct channel_oil *c_oil,
361 struct pim_interface *pim_ifp)
362{
363 bool old_mute;
364 bool new_mute;
365
366 /* If pim_ifp is not a part of the OIL there is nothing to do */
a9338fa4 367 if (!oil_if_has(c_oil, pim_ifp->mroute_vif_index))
5923b739
AK
368 return;
369
370 old_mute = !!(c_oil->oif_flags[pim_ifp->mroute_vif_index] &
371 PIM_OIF_FLAG_MUTE);
372 new_mute = pim_channel_eval_oif_mute(c_oil, pim_ifp);
373 if (old_mute == new_mute)
374 return;
375
376 if (new_mute)
377 c_oil->oif_flags[pim_ifp->mroute_vif_index] |=
378 PIM_OIF_FLAG_MUTE;
379 else
380 c_oil->oif_flags[pim_ifp->mroute_vif_index] &=
381 ~PIM_OIF_FLAG_MUTE;
382
15569c58 383 pim_upstream_mroute_add(c_oil, __func__);
5923b739
AK
384}
385
a155fed5
AK
386/* pim_upstream has been set or cleared on the c_oil. re-eval mute state
387 * on all existing OIFs
388 */
389static void pim_channel_update_mute(struct channel_oil *c_oil)
390{
391 struct pim_interface *pim_reg_ifp;
392 struct pim_interface *vxlan_ifp;
393
8c70a46b
DS
394 if (c_oil->pim->regiface) {
395 pim_reg_ifp = c_oil->pim->regiface->info;
396 if (pim_reg_ifp)
397 pim_channel_update_oif_mute(c_oil, pim_reg_ifp);
398 }
a155fed5
AK
399 vxlan_ifp = pim_vxlan_get_term_ifp(c_oil->pim);
400 if (vxlan_ifp)
401 pim_channel_update_oif_mute(c_oil, vxlan_ifp);
402}
403
d62a17ae 404int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
1b249e70 405 uint32_t proto_mask, const char *caller)
1865a44a 406{
d62a17ae 407 struct pim_interface *pim_ifp;
408 int old_ttl;
409
410 /*
411 * If we've gotten here we've gone bad, but let's
412 * not take down pim
413 */
414 if (!channel_oil) {
415 zlog_warn("Attempt to Add OIF for non-existent channel oil");
416 return -1;
417 }
1865a44a 418
d62a17ae 419 pim_ifp = oif->info;
1865a44a 420
d62a17ae 421 /* Prevent single protocol from subscribing same interface to
422 channel (S,G) multiple times */
423 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
424 if (PIM_DEBUG_MROUTE) {
d62a17ae 425 zlog_debug(
a9338fa4 426 "%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
15569c58
DA
427 __FILE__, __func__, proto_mask, oif->name,
428 pim_ifp->mroute_vif_index,
a9338fa4
DL
429 oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
430 oil_origin(channel_oil),
431 oil_mcastgrp(channel_oil));
d62a17ae 432 }
433 return -3;
434 }
435
436 /* Allow other protocol to request subscription of same interface to
437 * channel (S,G), we need to note this information
438 */
439 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index]
440 & PIM_OIF_FLAG_PROTO_ANY) {
441
d23756e9
SP
442 /* Updating time here is not required as this time has to
443 * indicate when the interface is added
444 */
445
d62a17ae 446 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
447 /* Check the OIF really exists before returning, and only log
448 warning otherwise */
a9338fa4 449 if (oil_if_has(channel_oil, pim_ifp->mroute_vif_index) < 1) {
dd4a4b56 450 zlog_warn(
a9338fa4 451 "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%pPAs,%pPAs)",
dd4a4b56
DS
452 __FILE__, __func__, proto_mask, oif->name,
453 pim_ifp->mroute_vif_index,
a9338fa4
DL
454 oil_if_has(channel_oil, pim_ifp->mroute_vif_index),
455 oil_origin(channel_oil),
456 oil_mcastgrp(channel_oil));
d62a17ae 457 }
458
b900ad16 459 if (PIM_DEBUG_MROUTE) {
b900ad16 460 zlog_debug(
a9338fa4
DL
461 "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u OIF=%s vif_index=%d added to 0x%x",
462 __func__, caller, oil_origin(channel_oil),
463 oil_mcastgrp(channel_oil),
b900ad16
AK
464 proto_mask, oif->name,
465 pim_ifp->mroute_vif_index,
466 channel_oil
467 ->oif_flags[pim_ifp->mroute_vif_index]);
468 }
d62a17ae 469 return 0;
470 }
471
a9338fa4 472 old_ttl = oil_if_has(channel_oil, pim_ifp->mroute_vif_index);
d62a17ae 473
474 if (old_ttl > 0) {
475 if (PIM_DEBUG_MROUTE) {
d62a17ae 476 zlog_debug(
a9338fa4 477 "%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%pPAs,%pPAs)",
15569c58 478 __FILE__, __func__, oif->name,
a9338fa4
DL
479 pim_ifp->mroute_vif_index,
480 oil_origin(channel_oil),
481 oil_mcastgrp(channel_oil));
d62a17ae 482 }
483 return -4;
484 }
485
a9338fa4 486 oil_if_set(channel_oil, pim_ifp->mroute_vif_index, PIM_MROUTE_MIN_TTL);
d62a17ae 487
5923b739
AK
488 /* Some OIFs are held in a muted state i.e. the PIM state machine
489 * decided to include the OIF but additional status check such as
490 * MLAG DF role prevent it from being activated for traffic
491 * forwarding.
492 */
493 if (pim_channel_eval_oif_mute(channel_oil, pim_ifp))
494 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |=
495 PIM_OIF_FLAG_MUTE;
496 else
497 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &=
498 ~PIM_OIF_FLAG_MUTE;
499
47e3ce59
SP
500 /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not
501 * valid to get installed in kernel.
c3156184 502 */
a9338fa4 503 if (*oil_parent(channel_oil) != MAXVIFS) {
15569c58 504 if (pim_upstream_mroute_add(channel_oil, __func__)) {
c3156184 505 if (PIM_DEBUG_MROUTE) {
c3156184 506 zlog_debug(
a9338fa4 507 "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%pPAs,%pPAs)",
15569c58 508 __FILE__, __func__, oif->name,
a9338fa4
DL
509 pim_ifp->mroute_vif_index,
510 oil_origin(channel_oil),
511 oil_mcastgrp(channel_oil));
c3156184 512 }
d62a17ae 513
a9338fa4
DL
514 oil_if_set(channel_oil, pim_ifp->mroute_vif_index,
515 old_ttl);
c3156184
SP
516 return -5;
517 }
d62a17ae 518 }
519
520 channel_oil->oif_creation[pim_ifp->mroute_vif_index] =
521 pim_time_monotonic_sec();
522 ++channel_oil->oil_size;
523 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
524
525 if (PIM_DEBUG_MROUTE) {
d62a17ae 526 zlog_debug(
a9338fa4
DL
527 "%s(%s): (S,G)=(%pPAs,%pPAs): proto_mask=%u OIF=%s vif_index=%d: DONE",
528 __func__, caller, oil_origin(channel_oil),
529 oil_mcastgrp(channel_oil),
530 proto_mask,
15569c58 531 oif->name, pim_ifp->mroute_vif_index);
d62a17ae 532 }
533
534 return 0;
1865a44a 535}
ce0ddb4e 536
d62a17ae 537int pim_channel_oil_empty(struct channel_oil *c_oil)
ce0ddb4e 538{
d62a17ae 539 if (!c_oil)
540 return 1;
d62a17ae 541
9e558d9a
AK
542 /* exclude pimreg from the OIL when checking if the inherited_oil is
543 * non-NULL.
544 * pimreg device (in all vrfs) uses a vifi of
545 * 0 (PIM_OIF_PIM_REGISTER_VIF) so we simply mfcc_ttls[0] */
a9338fa4
DL
546#if PIM_IPV == 4
547 static pim_mfcctl null_oil;
548
9e558d9a
AK
549 return !memcmp(&c_oil->oil.mfcc_ttls[1], &null_oil.mfcc_ttls[1],
550 sizeof(null_oil.mfcc_ttls) - sizeof(null_oil.mfcc_ttls[0]));
a9338fa4
DL
551#else
552 CPP_NOTICE("FIXME STUB");
553 return false;
554#endif
ce0ddb4e 555}