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