]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_oil.c
pbrd: initial fwmark support for pbr matches #4460
[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"
12e41d03 34
611925dc
DS
35// struct list *pim_channel_oil_list = NULL;
36// struct hash *pim_channel_oil_hash = NULL;
040d86ad 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
d62a17ae 64static int pim_channel_oil_compare(struct channel_oil *c1,
65 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
74df8d6d 86static bool pim_oil_equal(const void *arg1, const void *arg2)
040d86ad 87{
d62a17ae 88 const struct channel_oil *c1 = (const struct channel_oil *)arg1;
89 const struct channel_oil *c2 = (const struct channel_oil *)arg2;
040d86ad 90
d62a17ae 91 if ((c1->oil.mfcc_mcastgrp.s_addr == c2->oil.mfcc_mcastgrp.s_addr)
92 && (c1->oil.mfcc_origin.s_addr == c2->oil.mfcc_origin.s_addr))
74df8d6d 93 return true;
040d86ad 94
74df8d6d 95 return false;
040d86ad
DS
96}
97
d8b87afe 98static unsigned int pim_oil_hash_key(const void *arg)
040d86ad 99{
d8b87afe 100 const struct channel_oil *oil = arg;
040d86ad 101
d62a17ae 102 return jhash_2words(oil->oil.mfcc_mcastgrp.s_addr,
103 oil->oil.mfcc_origin.s_addr, 0);
040d86ad
DS
104}
105
611925dc 106void pim_oil_init(struct pim_instance *pim)
040d86ad 107{
9fb302f4
DS
108 char hash_name[64];
109
110 snprintf(hash_name, 64, "PIM %s Oil Hash", pim->vrf->name);
996c9314
LB
111 pim->channel_oil_hash = hash_create_size(8192, pim_oil_hash_key,
112 pim_oil_equal, hash_name);
d62a17ae 113
611925dc 114 pim->channel_oil_list = list_new();
611925dc
DS
115 pim->channel_oil_list->del = (void (*)(void *))pim_channel_oil_free;
116 pim->channel_oil_list->cmp =
d62a17ae 117 (int (*)(void *, void *))pim_channel_oil_compare;
040d86ad
DS
118}
119
611925dc 120void pim_oil_terminate(struct pim_instance *pim)
040d86ad 121{
611925dc 122 if (pim->channel_oil_list)
6a154c88 123 list_delete(&pim->channel_oil_list);
040d86ad 124
611925dc
DS
125 if (pim->channel_oil_hash)
126 hash_free(pim->channel_oil_hash);
127 pim->channel_oil_hash = NULL;
040d86ad
DS
128}
129
12e41d03
DL
130void pim_channel_oil_free(struct channel_oil *c_oil)
131{
d62a17ae 132 XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
12e41d03
DL
133}
134
4d9ad5dc
MS
135struct channel_oil *pim_find_channel_oil(struct pim_instance *pim,
136 struct prefix_sg *sg)
12e41d03 137{
d62a17ae 138 struct channel_oil *c_oil = NULL;
139 struct channel_oil lookup;
d270b216 140
d62a17ae 141 lookup.oil.mfcc_mcastgrp = sg->grp;
142 lookup.oil.mfcc_origin = sg->src;
d270b216 143
611925dc 144 c_oil = hash_lookup(pim->channel_oil_hash, &lookup);
d270b216 145
d62a17ae 146 return c_oil;
12e41d03
DL
147}
148
afb2f470
DS
149void pim_channel_oil_change_iif(struct pim_instance *pim,
150 struct channel_oil *c_oil,
151 int input_vif_index,
152 const char *name)
153{
154 int old_vif_index = c_oil->oil.mfcc_parent;
155 struct prefix_sg sg = {.src = c_oil->oil.mfcc_mcastgrp,
156 .grp = c_oil->oil.mfcc_origin};
157
158 if (c_oil->oil.mfcc_parent == input_vif_index) {
159 if (PIM_DEBUG_MROUTE_DETAIL)
160 zlog_debug("%s(%s): Existing channel oil %pSG4 already using %d as IIF",
161 __PRETTY_FUNCTION__, name, &sg,
162 input_vif_index);
163
164 return;
165 }
166
167 if (PIM_DEBUG_MROUTE_DETAIL)
168 zlog_debug("%s(%s): Changing channel oil %pSG4 IIF from %d to %d installed: %d",
169 __PRETTY_FUNCTION__, name, &sg,
170 c_oil->oil.mfcc_parent, input_vif_index,
171 c_oil->installed);
172
173 c_oil->oil.mfcc_parent = input_vif_index;
174 if (c_oil->installed) {
175 if (input_vif_index == MAXVIFS)
176 pim_mroute_del(c_oil, name);
177 else
178 pim_mroute_add(c_oil, name);
179 } else
180 if (old_vif_index == MAXVIFS)
181 pim_mroute_add(c_oil, name);
182
183 return;
184}
185
611925dc
DS
186struct channel_oil *pim_channel_oil_add(struct pim_instance *pim,
187 struct prefix_sg *sg,
8a3e7e9e 188 int input_vif_index, const char *name)
12e41d03 189{
d62a17ae 190 struct channel_oil *c_oil;
191 struct interface *ifp;
192
611925dc 193 c_oil = pim_find_channel_oil(pim, sg);
d62a17ae 194 if (c_oil) {
195 if (c_oil->oil.mfcc_parent != input_vif_index) {
196 c_oil->oil_inherited_rescan = 1;
8a3e7e9e 197 if (PIM_DEBUG_MROUTE_DETAIL)
d62a17ae 198 zlog_debug(
8a3e7e9e
DS
199 "%s: Existing channel oil %pSG4 points to %d, modifying to point at %d",
200 __PRETTY_FUNCTION__, sg,
d62a17ae 201 c_oil->oil.mfcc_parent,
202 input_vif_index);
203 }
afb2f470
DS
204 pim_channel_oil_change_iif(pim, c_oil, input_vif_index,
205 name);
d62a17ae 206 ++c_oil->oil_ref_count;
8a3e7e9e
DS
207 /* channel might be present prior to upstream */
208 c_oil->up = pim_upstream_find(pim, sg);
209
210 if (PIM_DEBUG_MROUTE)
211 zlog_debug(
212 "%s(%s): Existing oil for %pSG4 Ref Count: %d (Post Increment)",
213 __PRETTY_FUNCTION__, name, sg,
214 c_oil->oil_ref_count);
d62a17ae 215 return c_oil;
216 }
217
732c209c
SP
218 if (input_vif_index != MAXVIFS) {
219 ifp = pim_if_find_by_vif_index(pim, input_vif_index);
220 if (!ifp) {
221 /* warning only */
222 zlog_warn(
8a3e7e9e
DS
223 "%s:%s (S,G)=%pSG4 could not find input interface for input_vif_index=%d",
224 __PRETTY_FUNCTION__, name, sg, input_vif_index);
732c209c 225 }
d62a17ae 226 }
227
228 c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
d62a17ae 229
230 c_oil->oil.mfcc_mcastgrp = sg->grp;
231 c_oil->oil.mfcc_origin = sg->src;
611925dc 232 c_oil = hash_get(pim->channel_oil_hash, c_oil, hash_alloc_intern);
d62a17ae 233
234 c_oil->oil.mfcc_parent = input_vif_index;
235 c_oil->oil_ref_count = 1;
236 c_oil->installed = 0;
611925dc
DS
237 c_oil->up = pim_upstream_find(pim, sg);
238 c_oil->pim = pim;
d62a17ae 239
611925dc 240 listnode_add_sort(pim->channel_oil_list, c_oil);
d62a17ae 241
8a3e7e9e
DS
242 if (PIM_DEBUG_MROUTE)
243 zlog_debug(
244 "%s(%s): New oil for %pSG4 vif_index: %d Ref Count: 1 (Post Increment)",
245 __PRETTY_FUNCTION__, name, sg, input_vif_index);
d62a17ae 246 return c_oil;
12e41d03
DL
247}
248
8a3e7e9e 249void pim_channel_oil_del(struct channel_oil *c_oil, const char *name)
12e41d03 250{
8a3e7e9e
DS
251 if (PIM_DEBUG_MROUTE) {
252 struct prefix_sg sg = {.src = c_oil->oil.mfcc_mcastgrp,
253 .grp = c_oil->oil.mfcc_origin};
254
255 zlog_debug(
256 "%s(%s): Del oil for %pSG4, Ref Count: %d (Predecrement)",
257 __PRETTY_FUNCTION__, name, &sg, c_oil->oil_ref_count);
258 }
d62a17ae 259 --c_oil->oil_ref_count;
260
261 if (c_oil->oil_ref_count < 1) {
262 /*
263 * notice that listnode_delete() can't be moved
264 * into pim_channel_oil_free() because the later is
265 * called by list_delete_all_node()
266 */
267 c_oil->up = NULL;
611925dc
DS
268 listnode_delete(c_oil->pim->channel_oil_list, c_oil);
269 hash_release(c_oil->pim->channel_oil_hash, c_oil);
d62a17ae 270
271 pim_channel_oil_free(c_oil);
272 }
12e41d03 273}
1865a44a 274
d62a17ae 275int pim_channel_del_oif(struct channel_oil *channel_oil, struct interface *oif,
276 uint32_t proto_mask)
887fa014 277{
d62a17ae 278 struct pim_interface *pim_ifp;
279
280 zassert(channel_oil);
281 zassert(oif);
282
283 pim_ifp = oif->info;
284
285 /*
286 * Don't do anything if we've been asked to remove a source
287 * that is not actually on it.
288 */
289 if (!(channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask)) {
290 if (PIM_DEBUG_MROUTE) {
291 char group_str[INET_ADDRSTRLEN];
292 char source_str[INET_ADDRSTRLEN];
293 pim_inet4_dump("<group?>",
294 channel_oil->oil.mfcc_mcastgrp,
295 group_str, sizeof(group_str));
296 pim_inet4_dump("<source?>",
297 channel_oil->oil.mfcc_origin, source_str,
298 sizeof(source_str));
299 zlog_debug(
300 "%s %s: no existing protocol mask %u(%u) for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
301 __FILE__, __PRETTY_FUNCTION__, proto_mask,
302 channel_oil
303 ->oif_flags[pim_ifp->mroute_vif_index],
304 oif->name, pim_ifp->mroute_vif_index,
305 channel_oil->oil
306 .mfcc_ttls[pim_ifp->mroute_vif_index],
307 source_str, group_str);
308 }
309 return 0;
310 }
311
312 channel_oil->oif_flags[pim_ifp->mroute_vif_index] &= ~proto_mask;
313
314 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index]) {
315 if (PIM_DEBUG_MROUTE) {
316 char group_str[INET_ADDRSTRLEN];
317 char source_str[INET_ADDRSTRLEN];
318 pim_inet4_dump("<group?>",
319 channel_oil->oil.mfcc_mcastgrp,
320 group_str, sizeof(group_str));
321 pim_inet4_dump("<source?>",
322 channel_oil->oil.mfcc_origin, source_str,
323 sizeof(source_str));
324 zlog_debug(
325 "%s %s: other protocol masks remain for requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
326 __FILE__, __PRETTY_FUNCTION__, oif->name,
327 pim_ifp->mroute_vif_index,
328 channel_oil->oil
329 .mfcc_ttls[pim_ifp->mroute_vif_index],
330 source_str, group_str);
331 }
332 return 0;
333 }
334
335 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = 0;
336
337 if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
338 if (PIM_DEBUG_MROUTE) {
339 char group_str[INET_ADDRSTRLEN];
340 char source_str[INET_ADDRSTRLEN];
341 pim_inet4_dump("<group?>",
342 channel_oil->oil.mfcc_mcastgrp,
343 group_str, sizeof(group_str));
344 pim_inet4_dump("<source?>",
345 channel_oil->oil.mfcc_origin, source_str,
346 sizeof(source_str));
347 zlog_debug(
348 "%s %s: could not remove output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
349 __FILE__, __PRETTY_FUNCTION__, oif->name,
350 pim_ifp->mroute_vif_index, source_str,
351 group_str);
352 }
353 return -1;
887fa014 354 }
d62a17ae 355
356 --channel_oil->oil_size;
357
358 if (PIM_DEBUG_MROUTE) {
359 char group_str[INET_ADDRSTRLEN];
360 char source_str[INET_ADDRSTRLEN];
361 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp,
362 group_str, sizeof(group_str));
363 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin,
364 source_str, sizeof(source_str));
365 zlog_debug(
366 "%s %s: (S,G)=(%s,%s): proto_mask=%u IIF:%d OIF=%s vif_index=%d",
367 __FILE__, __PRETTY_FUNCTION__, source_str, group_str,
368 proto_mask, channel_oil->oil.mfcc_parent, oif->name,
369 pim_ifp->mroute_vif_index);
887fa014 370 }
d62a17ae 371
372 return 0;
887fa014
DS
373}
374
375
d62a17ae 376int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif,
377 uint32_t proto_mask)
1865a44a 378{
d62a17ae 379 struct pim_interface *pim_ifp;
380 int old_ttl;
7d973323 381 bool allow_iif_in_oil = false;
d62a17ae 382
383 /*
384 * If we've gotten here we've gone bad, but let's
385 * not take down pim
386 */
387 if (!channel_oil) {
388 zlog_warn("Attempt to Add OIF for non-existent channel oil");
389 return -1;
390 }
1865a44a 391
d62a17ae 392 pim_ifp = oif->info;
1865a44a 393
1865a44a 394#ifdef PIM_ENFORCE_LOOPFREE_MFC
d62a17ae 395 /*
396 Prevent creating MFC entry with OIF=IIF.
397
398 This is a protection against implementation mistakes.
399
400 PIM protocol implicitely ensures loopfree multicast topology.
401
402 IGMP must be protected against adding looped MFC entries created
403 by both source and receiver attached to the same interface. See
404 TODO T22.
50d06d9e 405 We shall allow igmp to create upstream when it is DR for the intf.
406 Assume RP reachable via non DR.
d62a17ae 407 */
50d06d9e 408 if ((channel_oil->up &&
409 PIM_UPSTREAM_FLAG_TEST_ALLOW_IIF_IN_OIL(channel_oil->up->flags)) ||
410 ((proto_mask == PIM_OIF_FLAG_PROTO_IGMP) && PIM_I_am_DR(pim_ifp))) {
7d973323
AK
411 allow_iif_in_oil = true;
412 }
413
414 if (!allow_iif_in_oil &&
415 pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
d62a17ae 416 channel_oil->oil_inherited_rescan = 1;
417 if (PIM_DEBUG_MROUTE) {
418 char group_str[INET_ADDRSTRLEN];
419 char source_str[INET_ADDRSTRLEN];
420 pim_inet4_dump("<group?>",
421 channel_oil->oil.mfcc_mcastgrp,
422 group_str, sizeof(group_str));
423 pim_inet4_dump("<source?>",
424 channel_oil->oil.mfcc_origin, source_str,
425 sizeof(source_str));
426 zlog_debug(
427 "%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
428 __FILE__, __PRETTY_FUNCTION__, proto_mask,
429 oif->name, pim_ifp->mroute_vif_index,
430 source_str, group_str);
431 }
432 return -2;
433 }
1865a44a
DS
434#endif
435
d62a17ae 436 /* Prevent single protocol from subscribing same interface to
437 channel (S,G) multiple times */
438 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
439 if (PIM_DEBUG_MROUTE) {
440 char group_str[INET_ADDRSTRLEN];
441 char source_str[INET_ADDRSTRLEN];
442 pim_inet4_dump("<group?>",
443 channel_oil->oil.mfcc_mcastgrp,
444 group_str, sizeof(group_str));
445 pim_inet4_dump("<source?>",
446 channel_oil->oil.mfcc_origin, source_str,
447 sizeof(source_str));
448 zlog_debug(
449 "%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
450 __FILE__, __PRETTY_FUNCTION__, proto_mask,
451 oif->name, pim_ifp->mroute_vif_index,
452 channel_oil->oil
453 .mfcc_ttls[pim_ifp->mroute_vif_index],
454 source_str, group_str);
455 }
456 return -3;
457 }
458
459 /* Allow other protocol to request subscription of same interface to
460 * channel (S,G), we need to note this information
461 */
462 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index]
463 & PIM_OIF_FLAG_PROTO_ANY) {
464
d23756e9
SP
465 /* Updating time here is not required as this time has to
466 * indicate when the interface is added
467 */
468
d62a17ae 469 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
470 /* Check the OIF really exists before returning, and only log
471 warning otherwise */
472 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
473 {
474 char group_str[INET_ADDRSTRLEN];
475 char source_str[INET_ADDRSTRLEN];
476 pim_inet4_dump("<group?>",
477 channel_oil->oil.mfcc_mcastgrp,
478 group_str, sizeof(group_str));
479 pim_inet4_dump("<source?>",
480 channel_oil->oil.mfcc_origin,
481 source_str, sizeof(source_str));
482 zlog_warn(
483 "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
484 __FILE__, __PRETTY_FUNCTION__,
485 proto_mask, oif->name,
486 pim_ifp->mroute_vif_index,
487 channel_oil->oil.mfcc_ttls
488 [pim_ifp->mroute_vif_index],
489 source_str, group_str);
490 }
491 }
492
493 return 0;
494 }
495
496 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
497
498 if (old_ttl > 0) {
499 if (PIM_DEBUG_MROUTE) {
500 char group_str[INET_ADDRSTRLEN];
501 char source_str[INET_ADDRSTRLEN];
502 pim_inet4_dump("<group?>",
503 channel_oil->oil.mfcc_mcastgrp,
504 group_str, sizeof(group_str));
505 pim_inet4_dump("<source?>",
506 channel_oil->oil.mfcc_origin, source_str,
507 sizeof(source_str));
508 zlog_debug(
509 "%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
510 __FILE__, __PRETTY_FUNCTION__, oif->name,
511 pim_ifp->mroute_vif_index, source_str,
512 group_str);
513 }
514 return -4;
515 }
516
517 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] =
518 PIM_MROUTE_MIN_TTL;
519
47e3ce59
SP
520 /* channel_oil->oil.mfcc_parent != MAXVIFS indicate this entry is not
521 * valid to get installed in kernel.
c3156184 522 */
47e3ce59 523 if (channel_oil->oil.mfcc_parent != MAXVIFS) {
c3156184
SP
524 if (pim_mroute_add(channel_oil, __PRETTY_FUNCTION__)) {
525 if (PIM_DEBUG_MROUTE) {
526 char group_str[INET_ADDRSTRLEN];
527 char source_str[INET_ADDRSTRLEN];
528 pim_inet4_dump("<group?>",
529 channel_oil->oil.mfcc_mcastgrp,
530 group_str, sizeof(group_str));
531 pim_inet4_dump("<source?>",
532 channel_oil->oil.mfcc_origin, source_str,
533 sizeof(source_str));
534 zlog_debug(
535 "%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
536 __FILE__, __PRETTY_FUNCTION__, oif->name,
537 pim_ifp->mroute_vif_index, source_str,
538 group_str);
539 }
d62a17ae 540
c3156184
SP
541 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index]
542 = old_ttl;
543 return -5;
544 }
d62a17ae 545 }
546
547 channel_oil->oif_creation[pim_ifp->mroute_vif_index] =
548 pim_time_monotonic_sec();
549 ++channel_oil->oil_size;
550 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
551
552 if (PIM_DEBUG_MROUTE) {
553 char group_str[INET_ADDRSTRLEN];
554 char source_str[INET_ADDRSTRLEN];
555 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp,
556 group_str, sizeof(group_str));
557 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin,
558 source_str, sizeof(source_str));
559 zlog_debug(
560 "%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
561 __FILE__, __PRETTY_FUNCTION__, source_str, group_str,
562 proto_mask, oif->name, pim_ifp->mroute_vif_index);
563 }
564
565 return 0;
1865a44a 566}
ce0ddb4e 567
d62a17ae 568int pim_channel_oil_empty(struct channel_oil *c_oil)
ce0ddb4e 569{
d62a17ae 570 static uint32_t zero[MAXVIFS];
571 static int inited = 0;
572
573 if (!c_oil)
574 return 1;
575 /*
576 * Not sure that this is necessary, but I would rather ensure
577 * that this works.
578 */
579 if (!inited) {
580 memset(&zero, 0, sizeof(uint32_t) * MAXVIFS);
581 inited = 1;
582 }
583
584 return !memcmp(c_oil->oif_flags, zero, MAXVIFS * sizeof(uint32_t));
ce0ddb4e 585}