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