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