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