]>
Commit | Line | Data |
---|---|---|
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 | 38 | char *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 | 64 | static 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 | 86 | static 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 | 98 | static 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 | 106 | void 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 | 120 | void 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 |
130 | void 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 |
135 | struct 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 |
149 | void 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 |
186 | struct 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 | 249 | void 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 | 275 | int 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 | 376 | int 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 | 568 | int 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 | } |