]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_oil.c
ospf6d: fix decimal area ID cli
[mirror_frr.git] / pimd / pim_oil.c
CommitLineData
12e41d03
DL
1/*
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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
12e41d03
DL
19*/
20
21#include <zebra.h>
22
23#include "log.h"
24#include "memory.h"
25#include "linklist.h"
744d91b3 26#include "if.h"
12e41d03
DL
27
28#include "pimd.h"
29#include "pim_oil.h"
30#include "pim_str.h"
31#include "pim_iface.h"
37653d4f 32#include "pim_time.h"
12e41d03
DL
33
34void pim_channel_oil_free(struct channel_oil *c_oil)
35{
36 XFREE(MTYPE_PIM_CHANNEL_OIL, c_oil);
37}
38
39static void pim_channel_oil_delete(struct channel_oil *c_oil)
40{
41 /*
42 notice that listnode_delete() can't be moved
43 into pim_channel_oil_free() because the later is
44 called by list_delete_all_node()
45 */
46 listnode_delete(qpim_channel_oil_list, c_oil);
47
48 pim_channel_oil_free(c_oil);
49}
50
51static struct channel_oil *channel_oil_new(struct in_addr group_addr,
52 struct in_addr source_addr,
53 int input_vif_index)
54{
55 struct channel_oil *c_oil;
56 struct interface *ifp_in;
57
58 ifp_in = pim_if_find_by_vif_index(input_vif_index);
59 if (!ifp_in) {
60 /* warning only */
61 char group_str[100];
62 char source_str[100];
63 pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
64 pim_inet4_dump("<source?>", source_addr, source_str, sizeof(source_str));
65 zlog_warn("%s: (S,G)=(%s,%s) could not find input interface for input_vif_index=%d",
66 __PRETTY_FUNCTION__,
67 source_str, group_str, input_vif_index);
68 }
69
70 c_oil = XCALLOC(MTYPE_PIM_CHANNEL_OIL, sizeof(*c_oil));
71 if (!c_oil) {
72 zlog_err("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
73 return 0;
74 }
75
76 c_oil->oil.mfcc_mcastgrp = group_addr;
77 c_oil->oil.mfcc_origin = source_addr;
78 c_oil->oil.mfcc_parent = input_vif_index;
79 c_oil->oil_ref_count = 1;
58302dc7 80 c_oil->installed = 0;
12e41d03
DL
81
82 zassert(c_oil->oil_size == 0);
83
84 return c_oil;
85}
86
87static struct channel_oil *pim_add_channel_oil(struct in_addr group_addr,
88 struct in_addr source_addr,
89 int input_vif_index)
90{
91 struct channel_oil *c_oil;
92
93 c_oil = channel_oil_new(group_addr, source_addr, input_vif_index);
94 if (!c_oil) {
95 zlog_warn("PIM XCALLOC(%zu) failure", sizeof(*c_oil));
96 return 0;
97 }
98
99 listnode_add(qpim_channel_oil_list, c_oil);
100
101 return c_oil;
102}
103
104static struct channel_oil *pim_find_channel_oil(struct in_addr group_addr,
105 struct in_addr source_addr)
106{
107 struct listnode *node;
108 struct channel_oil *c_oil;
109
110 for (ALL_LIST_ELEMENTS_RO(qpim_channel_oil_list, node, c_oil)) {
111 if ((group_addr.s_addr == c_oil->oil.mfcc_mcastgrp.s_addr) &&
112 (source_addr.s_addr == c_oil->oil.mfcc_origin.s_addr))
113 return c_oil;
114 }
115
116 return 0;
117}
118
119struct channel_oil *pim_channel_oil_add(struct in_addr group_addr,
120 struct in_addr source_addr,
121 int input_vif_index)
122{
123 struct channel_oil *c_oil;
124
125 c_oil = pim_find_channel_oil(group_addr, source_addr);
126 if (c_oil) {
127 ++c_oil->oil_ref_count;
128 return c_oil;
129 }
130
131 return pim_add_channel_oil(group_addr, source_addr, input_vif_index);
132}
133
134void pim_channel_oil_del(struct channel_oil *c_oil)
135{
136 --c_oil->oil_ref_count;
137
138 if (c_oil->oil_ref_count < 1) {
139 pim_channel_oil_delete(c_oil);
140 }
141}
1865a44a
DS
142
143int pim_channel_add_oif(struct channel_oil *channel_oil,
144 struct interface *oif,
145 uint32_t proto_mask)
146{
147 struct pim_interface *pim_ifp;
148 int old_ttl;
149
150 zassert(channel_oil);
151
152 pim_ifp = oif->info;
153
154 if (PIM_DEBUG_MROUTE) {
155 char group_str[100];
156 char source_str[100];
157 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
158 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
159 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d",
160 __FILE__, __PRETTY_FUNCTION__,
161 source_str, group_str,
162 proto_mask, oif->name, pim_ifp->mroute_vif_index);
163 }
164
1865a44a
DS
165#ifdef PIM_ENFORCE_LOOPFREE_MFC
166 /*
167 Prevent creating MFC entry with OIF=IIF.
168
169 This is a protection against implementation mistakes.
170
171 PIM protocol implicitely ensures loopfree multicast topology.
172
173 IGMP must be protected against adding looped MFC entries created
174 by both source and receiver attached to the same interface. See
175 TODO T22.
176 */
177 if (pim_ifp->mroute_vif_index == channel_oil->oil.mfcc_parent) {
e6dad1ab
DS
178 if (PIM_DEBUG_MROUTE)
179 {
180 char group_str[100];
181 char source_str[100];
182 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
183 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
184 zlog_debug("%s %s: refusing protocol mask %u request for IIF=OIF=%s (vif_index=%d) for channel (S,G)=(%s,%s)",
185 __FILE__, __PRETTY_FUNCTION__,
186 proto_mask, oif->name, pim_ifp->mroute_vif_index,
187 source_str, group_str);
188 }
1865a44a
DS
189 return -2;
190 }
191#endif
192
1865a44a
DS
193 /* Prevent single protocol from subscribing same interface to
194 channel (S,G) multiple times */
195 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & proto_mask) {
e6dad1ab
DS
196 if (PIM_DEBUG_MROUTE)
197 {
198 char group_str[100];
199 char source_str[100];
200 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
201 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
202 zlog_debug("%s %s: existing protocol mask %u requested OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
203 __FILE__, __PRETTY_FUNCTION__,
204 proto_mask, oif->name, pim_ifp->mroute_vif_index,
205 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
206 source_str, group_str);
207 }
1865a44a
DS
208 return -3;
209 }
210
211 /* Allow other protocol to request subscription of same interface to
212 channel (S,G) multiple times, by silently ignoring further
213 requests */
214 if (channel_oil->oif_flags[pim_ifp->mroute_vif_index] & PIM_OIF_FLAG_PROTO_ANY) {
215
216 /* Check the OIF really exists before returning, and only log
217 warning otherwise */
218 if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) {
e6dad1ab
DS
219 if (PIM_DEBUG_MROUTE)
220 {
221 char group_str[100];
222 char source_str[100];
223 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
224 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
225 zlog_debug("%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)",
226 __FILE__, __PRETTY_FUNCTION__,
227 proto_mask, oif->name, pim_ifp->mroute_vif_index,
228 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index],
229 source_str, group_str);
230 }
1865a44a
DS
231 }
232
233 return 0;
234 }
235
236 old_ttl = channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index];
237
238 if (old_ttl > 0) {
e6dad1ab
DS
239 if (PIM_DEBUG_MROUTE)
240 {
241 char group_str[100];
242 char source_str[100];
243 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
244 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
245 zlog_debug("%s %s: interface %s (vif_index=%d) is existing output for channel (S,G)=(%s,%s)",
246 __FILE__, __PRETTY_FUNCTION__,
247 oif->name, pim_ifp->mroute_vif_index,
248 source_str, group_str);
249 }
1865a44a
DS
250 return -4;
251 }
252
253 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = PIM_MROUTE_MIN_TTL;
254
c171d6d8 255 if (pim_mroute_add(channel_oil)) {
e6dad1ab
DS
256 if (PIM_DEBUG_MROUTE)
257 {
258 char group_str[100];
259 char source_str[100];
260 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
261 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
262 zlog_debug("%s %s: could not add output interface %s (vif_index=%d) for channel (S,G)=(%s,%s)",
263 __FILE__, __PRETTY_FUNCTION__,
264 oif->name, pim_ifp->mroute_vif_index,
265 source_str, group_str);
266 }
1865a44a
DS
267
268 channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] = old_ttl;
269 return -5;
270 }
271
272 channel_oil->oif_creation[pim_ifp->mroute_vif_index] = pim_time_monotonic_sec();
273 ++channel_oil->oil_size;
274 channel_oil->oif_flags[pim_ifp->mroute_vif_index] |= proto_mask;
275
276 if (PIM_DEBUG_MROUTE) {
277 char group_str[100];
278 char source_str[100];
279 pim_inet4_dump("<group?>", channel_oil->oil.mfcc_mcastgrp, group_str, sizeof(group_str));
280 pim_inet4_dump("<source?>", channel_oil->oil.mfcc_origin, source_str, sizeof(source_str));
281 zlog_debug("%s %s: (S,G)=(%s,%s): proto_mask=%u OIF=%s vif_index=%d: DONE",
282 __FILE__, __PRETTY_FUNCTION__,
283 source_str, group_str,
284 proto_mask, oif->name, pim_ifp->mroute_vif_index);
285 }
286
287 return 0;
288}